arnaucube
arnaucube/commonroutesAppPublic Self-hosted repository
commonroutesApp/www/lib/ui-leaflet/dist/ui-leaflet_dev_mapped.js
www/lib/ui-leaflet/dist/ui-leaflet_dev_mapped.jsRaw
   1/*!
   2*  ui-leaflet 2.0.0 2016-10-04
   3*  ui-leaflet - An AngularJS directive to easily interact with Leaflet maps
   4*  git: https://github.com/angular-ui/ui-leaflet
   5*/
   6(function(angular){
   7'use strict';
   8'use strict';
   9
  10angular.module('ui-leaflet', ['nemLogging']).directive('leaflet', function ($q, leafletData, leafletMapDefaults, leafletHelpers, leafletMapEvents) {
  11    return {
  12        restrict: "EA",
  13        replace: true,
  14        scope: {
  15            center: '=',
  16            lfCenter: '=',
  17            defaults: '=',
  18            maxbounds: '=',
  19            bounds: '=',
  20            markers: '=',
  21            legend: '=',
  22            geojson: '=',
  23            paths: '=',
  24            tiles: '=',
  25            layers: '=',
  26            controls: '=',
  27            decorations: '=',
  28            eventBroadcast: '=',
  29            watchOptions: '=',
  30            id: '@'
  31        },
  32        transclude: true,
  33        template: '<div class="angular-leaflet-map"><div ng-transclude></div></div>',
  34        controller: function controller($scope) {
  35            this._leafletMap = $q.defer();
  36            this.getMap = function () {
  37                return this._leafletMap.promise;
  38            };
  39
  40            this.getLeafletScope = function () {
  41                return $scope;
  42            };
  43        },
  44
  45        link: function link(scope, element, attrs, ctrl) {
  46            var isDefined = leafletHelpers.isDefined,
  47                defaults = leafletMapDefaults.setDefaults(scope.defaults, attrs.id),
  48                mapEvents = leafletMapEvents.getAvailableMapEvents(),
  49                addEvents = leafletMapEvents.addEvents;
  50
  51            scope.mapId = attrs.id;
  52            leafletData.setDirectiveControls({}, attrs.id);
  53
  54            // Set width and height utility functions
  55            function updateWidth() {
  56                if (isNaN(attrs.width)) {
  57                    element.css('width', attrs.width);
  58                } else {
  59                    element.css('width', attrs.width + 'px');
  60                }
  61            }
  62
  63            function updateHeight() {
  64                if (isNaN(attrs.height)) {
  65                    element.css('height', attrs.height);
  66                } else {
  67                    element.css('height', attrs.height + 'px');
  68                }
  69            }
  70
  71            // Create the Leaflet Map Object with the options
  72            var map = new L.Map(element[0], leafletMapDefaults.getMapCreationDefaults(attrs.id));
  73            ctrl._leafletMap.resolve(map);
  74
  75            // If the width attribute defined update css
  76            // Then watch if bound property changes and update css
  77            if (isDefined(attrs.width)) {
  78                updateWidth();
  79
  80                scope.$watch(function () {
  81                    return element[0].getAttribute('width');
  82                }, function () {
  83                    updateWidth();
  84                    map.invalidateSize();
  85                });
  86            }
  87
  88            // If the height attribute defined update css
  89            // Then watch if bound property changes and update css
  90            if (isDefined(attrs.height)) {
  91                updateHeight();
  92
  93                scope.$watch(function () {
  94                    return element[0].getAttribute('height');
  95                }, function () {
  96                    updateHeight();
  97                    map.invalidateSize();
  98                });
  99            }
 100
 101            if (!isDefined(attrs.center) && !isDefined(attrs.lfCenter)) {
 102                map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
 103            }
 104
 105            // If no layers nor tiles defined, set the default tileLayer
 106            if (!isDefined(attrs.tiles) && !isDefined(attrs.layers)) {
 107                var tileLayerObj = L.tileLayer(defaults.tileLayer, defaults.tileLayerOptions);
 108                tileLayerObj.addTo(map);
 109                leafletData.setTiles(tileLayerObj, attrs.id);
 110            }
 111
 112            // Set zoom control configuration
 113            if (isDefined(map.zoomControl) && isDefined(defaults.zoomControlPosition)) {
 114                map.zoomControl.setPosition(defaults.zoomControlPosition);
 115            }
 116
 117            if (isDefined(map.zoomControl) && defaults.zoomControl === false) {
 118                map.zoomControl.removeFrom(map);
 119            }
 120
 121            if (isDefined(map.zoomsliderControl) && isDefined(defaults.zoomsliderControl) && defaults.zoomsliderControl === false) {
 122                map.zoomsliderControl.removeFrom(map);
 123            }
 124
 125            // if no event-broadcast attribute, all events are broadcasted
 126            if (!isDefined(attrs.eventBroadcast)) {
 127                var logic = "broadcast";
 128                addEvents(map, attrs.id, mapEvents, "eventName", scope, logic);
 129            }
 130
 131            // Resolve the map object to the promises
 132            map.whenReady(function () {
 133                leafletData.setMap(map, attrs.id);
 134            });
 135
 136            scope.$on('$destroy', function () {
 137                leafletMapDefaults.reset();
 138                map.remove();
 139                leafletData.unresolveMap(attrs.id);
 140            });
 141
 142            //Handle request to invalidate the map size
 143            //Up scope using $scope.$emit('invalidateSize')
 144            //Down scope using $scope.$broadcast('invalidateSize')
 145            scope.$on('invalidateSize', function () {
 146                map.invalidateSize();
 147            });
 148        }
 149    };
 150});
 151
 152'use strict';
 153
 154(function () {
 155    angular.module('ui-leaflet').factory('eventManager', [function () {
 156        var EventManager = function EventManager() {
 157            this.listeners = {};
 158        };
 159
 160        EventManager.prototype = {
 161            addEventListener: function addEventListener(type, callback, scope) {
 162                var args = [];
 163                var numOfArgs = arguments.length;
 164                for (var i = 0; i < numOfArgs; i++) {
 165                    args.push(arguments[i]);
 166                }
 167                args = args.length > 3 ? args.splice(3, args.length - 1) : [];
 168                if (typeof this.listeners[type] !== "undefined") {
 169                    this.listeners[type].push({ scope: scope, callback: callback, args: args });
 170                } else {
 171                    this.listeners[type] = [{ scope: scope, callback: callback, args: args }];
 172                }
 173            },
 174            removeEventListener: function removeEventListener(type, callback, scope) {
 175                if (typeof this.listeners[type] !== "undefined") {
 176                    var numOfCallbacks = this.listeners[type].length;
 177                    var newArray = [];
 178                    for (var i = 0; i < numOfCallbacks; i++) {
 179                        var listener = this.listeners[type][i];
 180                        if (listener.scope === scope && listener.callback === callback) {} else {
 181                            newArray.push(listener);
 182                        }
 183                    }
 184                    this.listeners[type] = newArray;
 185                }
 186            },
 187            hasEventListener: function hasEventListener(type, callback, scope) {
 188                if (typeof this.listeners[type] !== "undefined") {
 189                    var numOfCallbacks = this.listeners[type].length;
 190                    if (callback === undefined && scope === undefined) {
 191                        return numOfCallbacks > 0;
 192                    }
 193                    for (var i = 0; i < numOfCallbacks; i++) {
 194                        var listener = this.listeners[type][i];
 195                        if ((scope ? listener.scope === scope : true) && listener.callback === callback) {
 196                            return true;
 197                        }
 198                    }
 199                }
 200                return false;
 201            },
 202            dispatch: function dispatch(type, target) {
 203                var numOfListeners = 0;
 204                var event = {
 205                    type: type,
 206                    target: target
 207                };
 208                var args = [];
 209                var numOfArgs = arguments.length;
 210                for (var i = 0; i < numOfArgs; i++) {
 211                    args.push(arguments[i]);
 212                }
 213                args = args.length > 2 ? args.splice(2, args.length - 1) : [];
 214                args = [event].concat(args);
 215                if (typeof this.listeners[type] !== "undefined") {
 216                    var numOfCallbacks = this.listeners[type].length;
 217                    for (var x = 0; x < numOfCallbacks; x++) {
 218                        var listener = this.listeners[type][x];
 219                        if (listener && listener.callback) {
 220                            var concatArgs = args.concat(listener.args);
 221                            listener.callback.apply(listener.scope, concatArgs);
 222                            numOfListeners += 1;
 223                        }
 224                    }
 225                }
 226            },
 227            getEvents: function getEvents() {
 228                var str = "";
 229                for (var type in this.listeners) {
 230                    var numOfCallbacks = this.listeners[type].length;
 231                    for (var i = 0; i < numOfCallbacks; i++) {
 232                        var listener = this.listeners[type][i];
 233                        str += listener.scope && listener.scope.className ? listener.scope.className : "anonymous";
 234                        str += " listen for '" + type + "'\n";
 235                    }
 236                }
 237                return str;
 238            }
 239        };
 240        return EventManager;
 241    }]).service('eventManager', function (EventManager) {
 242        return new EventManager();
 243    });
 244})();
 245
 246'use strict';
 247
 248angular.module('ui-leaflet').factory('leafletBoundsHelpers', function (leafletLogger, leafletHelpers) {
 249
 250    var isArray = leafletHelpers.isArray,
 251        isNumber = leafletHelpers.isNumber,
 252        isFunction = leafletHelpers.isFunction,
 253        isDefined = leafletHelpers.isDefined,
 254        $log = leafletLogger;
 255
 256    function _isValidBounds(bounds) {
 257        return angular.isDefined(bounds) && angular.isDefined(bounds.southWest) && angular.isDefined(bounds.northEast) && angular.isNumber(bounds.southWest.lat) && angular.isNumber(bounds.southWest.lng) && angular.isNumber(bounds.northEast.lat) && angular.isNumber(bounds.northEast.lng);
 258    }
 259
 260    return {
 261        createLeafletBounds: function createLeafletBounds(bounds) {
 262            if (_isValidBounds(bounds)) {
 263                return L.latLngBounds([bounds.southWest.lat, bounds.southWest.lng], [bounds.northEast.lat, bounds.northEast.lng]);
 264            }
 265        },
 266
 267        isValidBounds: _isValidBounds,
 268
 269        createBoundsFromArray: function createBoundsFromArray(boundsArray) {
 270            if (!(isArray(boundsArray) && boundsArray.length === 2 && isArray(boundsArray[0]) && isArray(boundsArray[1]) && boundsArray[0].length === 2 && boundsArray[1].length === 2 && isNumber(boundsArray[0][0]) && isNumber(boundsArray[0][1]) && isNumber(boundsArray[1][0]) && isNumber(boundsArray[1][1]))) {
 271                $log.error("[AngularJS - Leaflet] The bounds array is not valid.");
 272                return;
 273            }
 274
 275            return {
 276                northEast: {
 277                    lat: boundsArray[0][0],
 278                    lng: boundsArray[0][1]
 279                },
 280                southWest: {
 281                    lat: boundsArray[1][0],
 282                    lng: boundsArray[1][1]
 283                }
 284            };
 285        },
 286
 287        createBoundsFromLeaflet: function createBoundsFromLeaflet(lfBounds) {
 288            if (!(isDefined(lfBounds) && isFunction(lfBounds.getNorthEast) && isFunction(lfBounds.getSouthWest))) {
 289                $log.error("[AngularJS - Leaflet] The leaflet bounds is not valid object.");
 290                return;
 291            }
 292
 293            var northEast = lfBounds.getNorthEast(),
 294                southWest = lfBounds.getSouthWest();
 295
 296            return {
 297                northEast: {
 298                    lat: northEast.lat,
 299                    lng: northEast.lng
 300                },
 301                southWest: {
 302                    lat: southWest.lat,
 303                    lng: southWest.lng
 304                }
 305            };
 306        }
 307    };
 308});
 309
 310'use strict';
 311
 312angular.module('ui-leaflet').factory('leafletControlHelpers', function ($rootScope, leafletLogger, leafletHelpers, leafletLayerHelpers, leafletMapDefaults) {
 313    var isDefined = leafletHelpers.isDefined,
 314        isObject = leafletHelpers.isObject,
 315        createLayer = leafletLayerHelpers.createLayer,
 316        _controls = {},
 317        errorHeader = leafletHelpers.errorHeader + ' [Controls] ',
 318        $log = leafletLogger;
 319
 320    var _controlLayersMustBeVisible = function _controlLayersMustBeVisible(baselayers, overlays, mapId) {
 321        var defaults = leafletMapDefaults.getDefaults(mapId);
 322        if (!defaults.controls.layers.visible) {
 323            return false;
 324        }
 325
 326        var atLeastOneControlItemMustBeShown = false;
 327
 328        if (isObject(baselayers)) {
 329            Object.keys(baselayers).forEach(function (key) {
 330                var layer = baselayers[key];
 331                if (!isDefined(layer.layerOptions) || layer.layerOptions.showOnSelector !== false) {
 332                    atLeastOneControlItemMustBeShown = true;
 333                }
 334            });
 335        }
 336
 337        if (isObject(overlays)) {
 338            Object.keys(overlays).forEach(function (key) {
 339                var layer = overlays[key];
 340                if (!isDefined(layer.layerParams) || layer.layerParams.showOnSelector !== false) {
 341                    atLeastOneControlItemMustBeShown = true;
 342                }
 343            });
 344        }
 345
 346        return atLeastOneControlItemMustBeShown;
 347    };
 348
 349    var _createLayersControl = function _createLayersControl(mapId) {
 350        var defaults = leafletMapDefaults.getDefaults(mapId);
 351        var controlOptions = {
 352            collapsed: defaults.controls.layers.collapsed,
 353            position: defaults.controls.layers.position,
 354            autoZIndex: false
 355        };
 356
 357        angular.extend(controlOptions, defaults.controls.layers.options);
 358
 359        var control;
 360        if (defaults.controls.layers && isDefined(defaults.controls.layers.control)) {
 361            control = defaults.controls.layers.control.apply(this, [[], [], controlOptions]);
 362        } else {
 363            control = new L.control.layers([], [], controlOptions);
 364        }
 365
 366        return control;
 367    };
 368
 369    var controlTypes = {
 370        draw: {
 371            isPluginLoaded: function isPluginLoaded() {
 372                if (!angular.isDefined(L.Control.Draw)) {
 373                    $log.error(errorHeader + ' Draw plugin is not loaded.');
 374                    return false;
 375                }
 376                return true;
 377            },
 378            checkValidParams: function checkValidParams() /* params */{
 379                return true;
 380            },
 381            createControl: function createControl(params) {
 382                return new L.Control.Draw(params);
 383            }
 384        },
 385        scale: {
 386            isPluginLoaded: function isPluginLoaded() {
 387                return true;
 388            },
 389            checkValidParams: function checkValidParams() /* params */{
 390                return true;
 391            },
 392            createControl: function createControl(params) {
 393                return new L.control.scale(params);
 394            }
 395        },
 396        fullscreen: {
 397            isPluginLoaded: function isPluginLoaded() {
 398                if (!angular.isDefined(L.Control.Fullscreen)) {
 399                    $log.error(errorHeader + ' Fullscreen plugin is not loaded.');
 400                    return false;
 401                }
 402                return true;
 403            },
 404            checkValidParams: function checkValidParams() /* params */{
 405                return true;
 406            },
 407            createControl: function createControl(params) {
 408                return new L.Control.Fullscreen(params);
 409            }
 410        },
 411        search: {
 412            isPluginLoaded: function isPluginLoaded() {
 413                if (!angular.isDefined(L.Control.Search)) {
 414                    $log.error(errorHeader + ' Search plugin is not loaded.');
 415                    return false;
 416                }
 417                return true;
 418            },
 419            checkValidParams: function checkValidParams() /* params */{
 420                return true;
 421            },
 422            createControl: function createControl(params) {
 423                return new L.Control.Search(params);
 424            }
 425        },
 426        custom: {},
 427        minimap: {
 428            isPluginLoaded: function isPluginLoaded() {
 429                if (!angular.isDefined(L.Control.MiniMap)) {
 430                    $log.error(errorHeader + ' Minimap plugin is not loaded.');
 431                    return false;
 432                }
 433
 434                return true;
 435            },
 436            checkValidParams: function checkValidParams(params) {
 437                if (!isDefined(params.layer)) {
 438                    $log.warn(errorHeader + ' minimap "layer" option should be defined.');
 439                    return false;
 440                }
 441                return true;
 442            },
 443            createControl: function createControl(params) {
 444                var layer = createLayer(params.layer);
 445
 446                if (!isDefined(layer)) {
 447                    $log.warn(errorHeader + ' minimap control "layer" could not be created.');
 448                    return;
 449                }
 450
 451                return new L.Control.MiniMap(layer, params);
 452            }
 453        }
 454    };
 455
 456    return {
 457        layersControlMustBeVisible: _controlLayersMustBeVisible,
 458
 459        isValidControlType: function isValidControlType(type) {
 460            return Object.keys(controlTypes).indexOf(type) !== -1;
 461        },
 462
 463        createControl: function createControl(type, params) {
 464            if (!controlTypes[type].checkValidParams(params)) {
 465                return;
 466            }
 467
 468            return controlTypes[type].createControl(params);
 469        },
 470
 471        updateLayersControl: function updateLayersControl(map, mapId, loaded, baselayers, overlays, leafletLayers) {
 472            var i;
 473            var _layersControl = _controls[mapId];
 474            var mustBeLoaded = _controlLayersMustBeVisible(baselayers, overlays, mapId);
 475
 476            if (isDefined(_layersControl) && loaded) {
 477                for (i in leafletLayers.baselayers) {
 478                    _layersControl.removeLayer(leafletLayers.baselayers[i]);
 479                }
 480                for (i in leafletLayers.overlays) {
 481                    _layersControl.removeLayer(leafletLayers.overlays[i]);
 482                }
 483                map.removeControl(_layersControl);
 484                delete _controls[mapId];
 485            }
 486
 487            if (mustBeLoaded) {
 488                _layersControl = _createLayersControl(mapId);
 489                _controls[mapId] = _layersControl;
 490                for (i in baselayers) {
 491                    var hideOnSelector = isDefined(baselayers[i].layerOptions) && baselayers[i].layerOptions.showOnSelector === false;
 492                    if (!hideOnSelector && isDefined(leafletLayers.baselayers[i])) {
 493                        _layersControl.addBaseLayer(leafletLayers.baselayers[i], baselayers[i].name);
 494                    }
 495                }
 496                for (i in overlays) {
 497                    var hideOverlayOnSelector = isDefined(overlays[i].layerParams) && overlays[i].layerParams.showOnSelector === false;
 498                    if (!hideOverlayOnSelector && isDefined(leafletLayers.overlays[i])) {
 499                        _layersControl.addOverlay(leafletLayers.overlays[i], overlays[i].name);
 500                    }
 501                }
 502
 503                map.addControl(_layersControl);
 504            }
 505            return mustBeLoaded;
 506        },
 507
 508        destroyMapLayersControl: function destroyMapLayersControl(mapId) {
 509            delete _controls[mapId];
 510        }
 511    };
 512});
 513
 514'use strict';
 515
 516angular.module('ui-leaflet').service('leafletData', function (leafletLogger, $q, leafletHelpers) {
 517    var getDefer = leafletHelpers.getDefer,
 518        getUnresolvedDefer = leafletHelpers.getUnresolvedDefer,
 519        setResolvedDefer = leafletHelpers.setResolvedDefer;
 520    // $log = leafletLogger;
 521
 522    var _private = {};
 523    var self = this;
 524
 525    var upperFirst = function upperFirst(string) {
 526        return string.charAt(0).toUpperCase() + string.slice(1);
 527    };
 528
 529    var _privateItems = ['map', 'tiles', 'layers', 'paths', 'markers', 'geoJSON', 'UTFGrid', //odd ball on naming convention keeping to not break
 530    'decorations', 'directiveControls'];
 531
 532    //init
 533    _privateItems.forEach(function (itemName) {
 534        _private[itemName] = {};
 535    });
 536
 537    this.unresolveMap = function (scopeId) {
 538        var id = leafletHelpers.obtainEffectiveMapId(_private.map, scopeId);
 539        _privateItems.forEach(function (itemName) {
 540            _private[itemName][id] = undefined;
 541        });
 542    };
 543
 544    //int repetitive stuff (get and sets)
 545    _privateItems.forEach(function (itemName) {
 546        var name = upperFirst(itemName);
 547        self['set' + name] = function (lObject, scopeId) {
 548            var defer = getUnresolvedDefer(_private[itemName], scopeId);
 549            defer.resolve(lObject);
 550            setResolvedDefer(_private[itemName], scopeId);
 551        };
 552
 553        self['get' + name] = function (scopeId) {
 554            var defer = getDefer(_private[itemName], scopeId);
 555            return defer.promise;
 556        };
 557    });
 558});
 559
 560'use strict';
 561
 562angular.module('ui-leaflet').service('leafletDirectiveControlsHelpers', function (leafletLogger, leafletData, leafletHelpers) {
 563    var _isDefined = leafletHelpers.isDefined,
 564        _isString = leafletHelpers.isString,
 565        _isObject = leafletHelpers.isObject,
 566        _mainErrorHeader = leafletHelpers.errorHeader,
 567        $log = leafletLogger;
 568
 569    var _errorHeader = _mainErrorHeader + '[leafletDirectiveControlsHelpers';
 570
 571    var _extend = function _extend(id, thingToAddName, createFn, cleanFn) {
 572        var _fnHeader = _errorHeader + '.extend] ';
 573        var extender = {};
 574        if (!_isDefined(thingToAddName)) {
 575            $log.error(_fnHeader + 'thingToAddName cannot be undefined');
 576            return;
 577        }
 578
 579        if (_isString(thingToAddName) && _isDefined(createFn) && _isDefined(cleanFn)) {
 580            extender[thingToAddName] = {
 581                create: createFn,
 582                clean: cleanFn
 583            };
 584        } else if (_isObject(thingToAddName) && !_isDefined(createFn) && !_isDefined(cleanFn)) {
 585            extender = thingToAddName;
 586        } else {
 587            $log.error(_fnHeader + 'incorrect arguments');
 588            return;
 589        }
 590
 591        //add external control to create / destroy markers without a watch
 592        leafletData.getDirectiveControls().then(function (controls) {
 593            angular.extend(controls, extender);
 594            leafletData.setDirectiveControls(controls, id);
 595        });
 596    };
 597
 598    return {
 599        extend: _extend
 600    };
 601});
 602
 603'use strict';
 604
 605angular.module('ui-leaflet').service('leafletGeoJsonHelpers', function (leafletHelpers, leafletIterators) {
 606    var lHlp = leafletHelpers,
 607        lIt = leafletIterators;
 608    var Point = function Point(lat, lng) {
 609        this.lat = lat;
 610        this.lng = lng;
 611        return this;
 612    };
 613
 614    var _getLat = function _getLat(value) {
 615        if (Array.isArray(value) && value.length === 2) {
 616            return value[1];
 617        } else if (lHlp.isDefined(value.type) && value.type === 'Point') {
 618            return +value.coordinates[1];
 619        } else {
 620            return +value.lat;
 621        }
 622    };
 623
 624    var _getLng = function _getLng(value) {
 625        if (Array.isArray(value) && value.length === 2) {
 626            return value[0];
 627        } else if (lHlp.isDefined(value.type) && value.type === 'Point') {
 628            return +value.coordinates[0];
 629        } else {
 630            return +value.lng;
 631        }
 632    };
 633
 634    var _validateCoords = function _validateCoords(coords) {
 635        if (lHlp.isUndefined(coords)) {
 636            return false;
 637        }
 638        if (lHlp.isArray(coords)) {
 639            if (coords.length === 2 && lHlp.isNumber(coords[0]) && lHlp.isNumber(coords[1])) {
 640                return true;
 641            }
 642        } else if (lHlp.isDefined(coords.type)) {
 643            if (coords.type === 'Point' && lHlp.isArray(coords.coordinates) && coords.coordinates.length === 2 && lHlp.isNumber(coords.coordinates[0]) && lHlp.isNumber(coords.coordinates[1])) {
 644                return true;
 645            }
 646        }
 647
 648        var ret = lIt.all(['lat', 'lng'], function (pos) {
 649            return lHlp.isDefined(coords[pos]) && lHlp.isNumber(coords[pos]);
 650        });
 651        return ret;
 652    };
 653
 654    var _getCoords = function _getCoords(value) {
 655        if (!value || !_validateCoords(value)) {
 656            return;
 657        }
 658        var p = null;
 659        if (Array.isArray(value) && value.length === 2) {
 660            p = new Point(value[1], value[0]);
 661        } else if (lHlp.isDefined(value.type) && value.type === 'Point') {
 662            p = new Point(value.coordinates[1], value.coordinates[0]);
 663        } else {
 664            return value;
 665        }
 666        //note angular.merge is avail in angular 1.4.X we might want to fill it here
 667        return angular.extend(value, p); //tap on lat, lng if it doesnt exist
 668    };
 669
 670    return {
 671        getLat: _getLat,
 672        getLng: _getLng,
 673        validateCoords: _validateCoords,
 674        getCoords: _getCoords
 675    };
 676});
 677
 678'use strict';
 679
 680angular.module('ui-leaflet').service('leafletHelpers', function ($q, $log, $timeout) {
 681    var _errorHeader = '[ui-leaflet] ';
 682    var _copy = angular.copy;
 683    var _clone = _copy;
 684    /*
 685    For parsing paths to a field in an object
 686     Example:
 687    var obj = {
 688        bike:{
 689         1: 'hi'
 690         2: 'foo'
 691        }
 692    };
 693    _getObjectValue(obj,"bike.1") returns 'hi'
 694    this is getPath in ui-gmap
 695     */
 696    var _getObjectValue = function _getObjectValue(object, pathStr) {
 697        var obj;
 698        if (!object || !angular.isObject(object)) return;
 699        //if the key is not a sting then we already have the value
 700        if (pathStr === null || !angular.isString(pathStr)) {
 701            return pathStr;
 702        }
 703        obj = object;
 704        pathStr.split('.').forEach(function (value) {
 705            if (obj) {
 706                obj = obj[value];
 707            }
 708        });
 709        return obj;
 710    };
 711
 712    /*
 713     Object Array Notation
 714     _getObjectArrayPath("bike.one.two")
 715     returns:
 716     'bike["one"]["two"]'
 717     */
 718    var _getObjectArrayPath = function _getObjectArrayPath(pathStr) {
 719        return pathStr.split('.').reduce(function (previous, current) {
 720            return previous + '["' + current + '"]';
 721        });
 722    };
 723
 724    /* Object Dot Notation
 725     _getObjectPath(["bike","one","two"])
 726     returns:
 727     "bike.one.two"
 728     */
 729    var _getObjectDotPath = function _getObjectDotPath(arrayOfStrings) {
 730        return arrayOfStrings.reduce(function (previous, current) {
 731            return previous + '.' + current;
 732        });
 733    };
 734
 735    function _obtainEffectiveMapId(d, mapId) {
 736        var id, i;
 737        if (!angular.isDefined(mapId)) {
 738            if (Object.keys(d).length === 0) {
 739                id = "main";
 740            } else if (Object.keys(d).length >= 1) {
 741                for (i in d) {
 742                    if (d.hasOwnProperty(i)) {
 743                        id = i;
 744                    }
 745                }
 746            } else {
 747                $log.error(_errorHeader + "- You have more than 1 map on the DOM, you must provide the map ID to the leafletData.getXXX call");
 748            }
 749        } else {
 750            id = mapId;
 751        }
 752
 753        return id;
 754    }
 755
 756    function _getUnresolvedDefer(d, mapId) {
 757        var id = _obtainEffectiveMapId(d, mapId),
 758            defer;
 759
 760        if (!angular.isDefined(d[id]) || d[id].resolvedDefer === true) {
 761            defer = $q.defer();
 762            d[id] = {
 763                defer: defer,
 764                resolvedDefer: false
 765            };
 766        } else {
 767            defer = d[id].defer;
 768        }
 769
 770        return defer;
 771    }
 772
 773    var _isDefined = function _isDefined(value) {
 774        return angular.isDefined(value) && value !== null;
 775    };
 776    var _isUndefined = function _isUndefined(value) {
 777        return !_isDefined(value);
 778    };
 779
 780    // BEGIN DIRECT PORT FROM AngularJS code base
 781
 782    var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
 783
 784    var MOZ_HACK_REGEXP = /^moz([A-Z])/;
 785
 786    var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
 787
 788    /**
 789    Converts snake_case to camelCase.
 790    Also there is special case for Moz prefix starting with upper case letter.
 791    @param name Name to normalize
 792     */
 793
 794    var camelCase = function camelCase(name) {
 795        return name.replace(SPECIAL_CHARS_REGEXP, function (_, separator, letter, offset) {
 796            if (offset) {
 797                return letter.toUpperCase();
 798            } else {
 799                return letter;
 800            }
 801        }).replace(MOZ_HACK_REGEXP, "Moz$1");
 802    };
 803
 804    /**
 805        Converts all accepted directives format into proper directive name.
 806        @param name Name to normalize
 807    */
 808
 809    var directiveNormalize = function directiveNormalize(name) {
 810        return camelCase(name.replace(PREFIX_REGEXP, ""));
 811    };
 812    // END AngularJS port
 813
 814    var _watchTrapDelayMilliSec = 10;
 815
 816    var _modelChangeInDirective = function _modelChangeInDirective(trapObj, trapField, cbToExec) {
 817        if (!trapObj) throw new Error(_errorHeader + 'trapObj is undefined');
 818        if (!trapField) throw new Error(_errorHeader + 'trapField is undefined');
 819
 820        trapObj[trapField] = true;
 821        var ret = cbToExec();
 822        $timeout(function () {
 823            trapObj[trapField] = false;
 824        }, _watchTrapDelayMilliSec);
 825        return ret;
 826    };
 827
 828    return {
 829        watchTrapDelayMilliSec: _watchTrapDelayMilliSec,
 830        modelChangeInDirective: _modelChangeInDirective,
 831        camelCase: camelCase,
 832        directiveNormalize: directiveNormalize,
 833        copy: _copy,
 834        clone: _clone,
 835        errorHeader: _errorHeader,
 836        getObjectValue: _getObjectValue,
 837        getObjectArrayPath: _getObjectArrayPath,
 838        getObjectDotPath: _getObjectDotPath,
 839        defaultTo: function defaultTo(val, _default) {
 840            return _isDefined(val) ? val : _default;
 841        },
 842        //mainly for checking attributes of directives lets keep this minimal (on what we accept)
 843        isTruthy: function isTruthy(val) {
 844            return val === 'true' || val === true;
 845        },
 846        //Determine if a reference is {}
 847        isEmpty: function isEmpty(value) {
 848            return Object.keys(value).length === 0;
 849        },
 850
 851        //Determine if a reference is undefined or {}
 852        isUndefinedOrEmpty: function isUndefinedOrEmpty(value) {
 853            return angular.isUndefined(value) || value === null || Object.keys(value).length === 0;
 854        },
 855
 856        // Determine if a reference is defined
 857        isDefined: _isDefined,
 858        isUndefined: _isUndefined,
 859        isNumber: angular.isNumber,
 860        isString: angular.isString,
 861        isArray: angular.isArray,
 862        isObject: angular.isObject,
 863        isFunction: angular.isFunction,
 864        equals: angular.equals,
 865
 866        isValidCenter: function isValidCenter(center) {
 867            return angular.isDefined(center) && angular.isNumber(center.lat) && angular.isNumber(center.lng) && angular.isNumber(center.zoom);
 868        },
 869
 870        isValidPoint: function isValidPoint(point) {
 871            if (!angular.isDefined(point)) {
 872                return false;
 873            }
 874            if (angular.isArray(point)) {
 875                return point.length === 2 && angular.isNumber(point[0]) && angular.isNumber(point[1]);
 876            }
 877            return angular.isNumber(point.lat) && angular.isNumber(point.lng);
 878        },
 879
 880        isSameCenterOnMap: function isSameCenterOnMap(centerModel, map) {
 881            var mapCenter = map.getCenter();
 882            var zoom = map.getZoom();
 883            if (centerModel.lat && centerModel.lng && mapCenter.lat.toFixed(4) === centerModel.lat.toFixed(4) && mapCenter.lng.toFixed(4) === centerModel.lng.toFixed(4) && zoom === centerModel.zoom) {
 884                return true;
 885            }
 886            return false;
 887        },
 888
 889        safeApply: function safeApply($scope, fn) {
 890            var phase = $scope.$root.$$phase;
 891            if (phase === '$apply' || phase === '$digest') {
 892                $scope.$eval(fn);
 893            } else {
 894                $scope.$evalAsync(fn);
 895            }
 896        },
 897
 898        obtainEffectiveMapId: _obtainEffectiveMapId,
 899
 900        getDefer: function getDefer(d, mapId) {
 901            var id = _obtainEffectiveMapId(d, mapId),
 902                defer;
 903            if (!angular.isDefined(d[id]) || d[id].resolvedDefer === false) {
 904                defer = _getUnresolvedDefer(d, mapId);
 905            } else {
 906                defer = d[id].defer;
 907            }
 908            return defer;
 909        },
 910
 911        getUnresolvedDefer: _getUnresolvedDefer,
 912
 913        setResolvedDefer: function setResolvedDefer(d, mapId) {
 914            var id = _obtainEffectiveMapId(d, mapId);
 915            d[id].resolvedDefer = true;
 916        },
 917
 918        rangeIsSupported: function rangeIsSupported() {
 919            var testrange = document.createElement('input');
 920            testrange.setAttribute('type', 'range');
 921            return testrange.type === 'range';
 922        },
 923
 924        FullScreenControlPlugin: {
 925            isLoaded: function isLoaded() {
 926                return angular.isDefined(L.Control.Fullscreen);
 927            }
 928        },
 929
 930        MiniMapControlPlugin: {
 931            isLoaded: function isLoaded() {
 932                return angular.isDefined(L.Control.MiniMap);
 933            }
 934        },
 935
 936        AwesomeMarkersPlugin: {
 937            isLoaded: function isLoaded() {
 938                return angular.isDefined(L.AwesomeMarkers) && angular.isDefined(L.AwesomeMarkers.Icon);
 939            },
 940            is: function is(icon) {
 941                if (this.isLoaded()) {
 942                    return icon instanceof L.AwesomeMarkers.Icon;
 943                } else {
 944                    return false;
 945                }
 946            },
 947            equal: function equal(iconA, iconB) {
 948                if (!this.isLoaded()) {
 949                    return false;
 950                }
 951                if (this.is(iconA)) {
 952                    return angular.equals(iconA, iconB);
 953                } else {
 954                    return false;
 955                }
 956            }
 957        },
 958
 959        VectorMarkersPlugin: {
 960            isLoaded: function isLoaded() {
 961                return angular.isDefined(L.VectorMarkers) && angular.isDefined(L.VectorMarkers.Icon);
 962            },
 963            is: function is(icon) {
 964                if (this.isLoaded()) {
 965                    return icon instanceof L.VectorMarkers.Icon;
 966                } else {
 967                    return false;
 968                }
 969            },
 970            equal: function equal(iconA, iconB) {
 971                if (!this.isLoaded()) {
 972                    return false;
 973                }
 974                if (this.is(iconA)) {
 975                    return angular.equals(iconA, iconB);
 976                } else {
 977                    return false;
 978                }
 979            }
 980        },
 981
 982        DomMarkersPlugin: {
 983            isLoaded: function isLoaded() {
 984                if (angular.isDefined(L.DomMarkers) && angular.isDefined(L.DomMarkers.Icon)) {
 985                    return true;
 986                } else {
 987                    return false;
 988                }
 989            },
 990            is: function is(icon) {
 991                if (this.isLoaded()) {
 992                    return icon instanceof L.DomMarkers.Icon;
 993                } else {
 994                    return false;
 995                }
 996            },
 997            equal: function equal(iconA, iconB) {
 998                if (!this.isLoaded()) {
 999                    return false;
1000                }
1001                if (this.is(iconA)) {
1002                    return angular.equals(iconA, iconB);
1003                } else {
1004                    return false;
1005                }
1006            }
1007        },
1008
1009        PolylineDecoratorPlugin: {
1010            isLoaded: function isLoaded() {
1011                if (angular.isDefined(L.PolylineDecorator)) {
1012                    return true;
1013                } else {
1014                    return false;
1015                }
1016            },
1017            is: function is(decoration) {
1018                if (this.isLoaded()) {
1019                    return decoration instanceof L.PolylineDecorator;
1020                } else {
1021                    return false;
1022                }
1023            },
1024            equal: function equal(decorationA, decorationB) {
1025                if (!this.isLoaded()) {
1026                    return false;
1027                }
1028                if (this.is(decorationA)) {
1029                    return angular.equals(decorationA, decorationB);
1030                } else {
1031                    return false;
1032                }
1033            }
1034        },
1035
1036        MakiMarkersPlugin: {
1037            isLoaded: function isLoaded() {
1038                if (angular.isDefined(L.MakiMarkers) && angular.isDefined(L.MakiMarkers.Icon)) {
1039                    return true;
1040                } else {
1041                    return false;
1042                }
1043            },
1044            is: function is(icon) {
1045                if (this.isLoaded()) {
1046                    return icon instanceof L.MakiMarkers.Icon;
1047                } else {
1048                    return false;
1049                }
1050            },
1051            equal: function equal(iconA, iconB) {
1052                if (!this.isLoaded()) {
1053                    return false;
1054                }
1055                if (this.is(iconA)) {
1056                    return angular.equals(iconA, iconB);
1057                } else {
1058                    return false;
1059                }
1060            }
1061        },
1062        ExtraMarkersPlugin: {
1063            isLoaded: function isLoaded() {
1064                if (angular.isDefined(L.ExtraMarkers) && angular.isDefined(L.ExtraMarkers.Icon)) {
1065                    return true;
1066                } else {
1067                    return false;
1068                }
1069            },
1070            is: function is(icon) {
1071                if (this.isLoaded()) {
1072                    return icon instanceof L.ExtraMarkers.Icon;
1073                } else {
1074                    return false;
1075                }
1076            },
1077            equal: function equal(iconA, iconB) {
1078                if (!this.isLoaded()) {
1079                    return false;
1080                }
1081                if (this.is(iconA)) {
1082                    return angular.equals(iconA, iconB);
1083                } else {
1084                    return false;
1085                }
1086            }
1087        },
1088        LabelPlugin: {
1089            isLoaded: function isLoaded() {
1090                return angular.isDefined(L.Label);
1091            },
1092            is: function is(layer) {
1093                if (this.isLoaded()) {
1094                    return layer instanceof L.MarkerClusterGroup;
1095                } else {
1096                    return false;
1097                }
1098            }
1099        },
1100        MarkerClusterPlugin: {
1101            isLoaded: function isLoaded() {
1102                return angular.isDefined(L.MarkerClusterGroup);
1103            },
1104            is: function is(layer) {
1105                if (this.isLoaded()) {
1106                    return layer instanceof L.MarkerClusterGroup;
1107                } else {
1108                    return false;
1109                }
1110            }
1111        },
1112        GeoJSONPlugin: {
1113            isLoaded: function isLoaded() {
1114                return angular.isDefined(L.TileLayer.GeoJSON);
1115            },
1116            is: function is(layer) {
1117                if (this.isLoaded()) {
1118                    return layer instanceof L.TileLayer.GeoJSON;
1119                } else {
1120                    return false;
1121                }
1122            }
1123        },
1124        CartoDB: {
1125            isLoaded: function isLoaded() {
1126                return cartodb;
1127            },
1128            is: function is() /*layer*/{
1129                return true;
1130                /*
1131                if (this.isLoaded()) {
1132                    return layer instanceof L.TileLayer.GeoJSON;
1133                } else {
1134                    return false;
1135                }*/
1136            }
1137        },
1138        Leaflet: {
1139            DivIcon: {
1140                is: function is(icon) {
1141                    return icon instanceof L.DivIcon;
1142                },
1143                equal: function equal(iconA, iconB) {
1144                    if (this.is(iconA)) {
1145                        return angular.equals(iconA, iconB);
1146                    } else {
1147                        return false;
1148                    }
1149                }
1150            },
1151            Icon: {
1152                is: function is(icon) {
1153                    return icon instanceof L.Icon;
1154                },
1155                equal: function equal(iconA, iconB) {
1156                    if (this.is(iconA)) {
1157                        return angular.equals(iconA, iconB);
1158                    } else {
1159                        return false;
1160                    }
1161                }
1162            }
1163        },
1164        /*
1165         watchOptions - object to set deep nested watches and turn off watches all together
1166         (rely on control / functional updates)
1167         watchOptions - Object
1168             type: string. //One of ['watch', 'watchCollection', 'watchDeep', null]
1169             individual
1170                 type: string
1171         */
1172        //legacy defaults
1173        watchOptions: {
1174            type: 'watchDeep',
1175            individual: {
1176                type: 'watchDeep'
1177            }
1178        }
1179    };
1180});
1181
1182'use strict';
1183
1184angular.module('ui-leaflet').service('leafletIterators', function (leafletLogger, leafletHelpers) {
1185
1186  var lHlp = leafletHelpers,
1187      errorHeader = leafletHelpers.errorHeader + 'leafletIterators: ';
1188
1189  //BEGIN COPY from underscore
1190  var _keys = Object.keys;
1191  var _isFunction = lHlp.isFunction;
1192  var _isObject = lHlp.isObject;
1193  var $log = leafletLogger;
1194
1195  // Helper for collection methods to determine whether a collection
1196  // should be iterated as an array or as an object
1197  // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
1198  var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
1199
1200  var _isArrayLike = function _isArrayLike(collection) {
1201    var length = collection !== null && collection.length;
1202    return lHlp.isNumber(length) && length >= 0 && length <= MAX_ARRAY_INDEX;
1203  };
1204
1205  // Keep the identity function around for default iteratees.
1206  var _identity = function _identity(value) {
1207    return value;
1208  };
1209
1210  var _property = function _property(key) {
1211    return function (obj) {
1212      return obj === null ? void 0 : obj[key];
1213    };
1214  };
1215
1216  // Internal function that returns an efficient (for current engines) version
1217  // of the passed-in callback, to be repeatedly applied in other Underscore
1218  // functions.
1219  var optimizeCb = function optimizeCb(func, context, argCount) {
1220    if (context === void 0) return func;
1221    switch (argCount === null ? 3 : argCount) {
1222      case 1:
1223        return function (value) {
1224          return func.call(context, value);
1225        };
1226      case 2:
1227        return function (value, other) {
1228          return func.call(context, value, other);
1229        };
1230      case 3:
1231        return function (value, index, collection) {
1232          return func.call(context, value, index, collection);
1233        };
1234      case 4:
1235        return function (accumulator, value, index, collection) {
1236          return func.call(context, accumulator, value, index, collection);
1237        };
1238    }
1239    return function () {
1240      return func.apply(context, arguments);
1241    };
1242  };
1243
1244  // An internal function for creating assigner functions.
1245  var createAssigner = function createAssigner(keysFunc, undefinedOnly) {
1246    return function (obj) {
1247      var length = arguments.length;
1248      if (length < 2 || obj === null) return obj;
1249      for (var index = 1; index < length; index++) {
1250        var source = arguments[index],
1251            keys = keysFunc(source),
1252            l = keys.length;
1253        for (var i = 0; i < l; i++) {
1254          var key = keys[i];
1255          if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
1256        }
1257      }
1258      return obj;
1259    };
1260  };
1261
1262  // Assigns a given object with all the own properties in the passed-in object(s)
1263  // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
1264  var _extendOwn,
1265      _assign = null;
1266  _extendOwn = _assign = createAssigner(_keys);
1267
1268  // Returns whether an object has a given set of `key:value` pairs.
1269  var _isMatch = function _isMatch(object, attrs) {
1270    var keys = _keys(attrs),
1271        length = keys.length;
1272    if (object === null) return !length;
1273    var obj = Object(object);
1274    for (var i = 0; i < length; i++) {
1275      var key = keys[i];
1276      if (attrs[key] !== obj[key] || !(key in obj)) return false;
1277    }
1278    return true;
1279  };
1280
1281  // Returns a predicate for checking whether an object has a given set of
1282  // `key:value` pairs.
1283  var _matcher,
1284      _matches = null;
1285  _matcher = _matches = function _matches(attrs) {
1286    attrs = _extendOwn({}, attrs);
1287    return function (obj) {
1288      return _isMatch(obj, attrs);
1289    };
1290  };
1291
1292  // A mostly-internal function to generate callbacks that can be applied
1293  // to each element in a collection, returning the desired result — either
1294  // identity, an arbitrary callback, a property matcher, or a property accessor.
1295  var cb = function cb(value, context, argCount) {
1296    if (value === null) return _identity;
1297    if (_isFunction(value)) return optimizeCb(value, context, argCount);
1298    if (_isObject(value)) return _matcher(value);
1299    return _property(value);
1300  };
1301
1302  var _every,
1303      _all = null;
1304  _every = _all = function _all(obj, predicate, context) {
1305    predicate = cb(predicate, context);
1306    var keys = !_isArrayLike(obj) && _keys(obj),
1307        length = (keys || obj).length;
1308    for (var index = 0; index < length; index++) {
1309      var currentKey = keys ? keys[index] : index;
1310      if (!predicate(obj[currentKey], currentKey, obj)) return false;
1311    }
1312    return true;
1313  };
1314
1315  //END COPY fron underscore
1316
1317  var _hasErrors = function _hasErrors(collection, cb, ignoreCollection, cbName) {
1318    if (!ignoreCollection) {
1319      if (!lHlp.isDefined(collection) || !lHlp.isDefined(cb)) {
1320        return true;
1321      }
1322    }
1323    if (!lHlp.isFunction(cb)) {
1324      cbName = lHlp.defaultTo(cb, 'cb');
1325      $log.error(errorHeader + cbName + ' is not a function');
1326      return true;
1327    }
1328    return false;
1329  };
1330
1331  var _iterate = function _iterate(collection, externalCb, internalCb) {
1332    if (_hasErrors(undefined, internalCb, true, 'internalCb')) {
1333      return;
1334    }
1335    if (!_hasErrors(collection, externalCb)) {
1336      for (var key in collection) {
1337        if (collection.hasOwnProperty(key)) {
1338          internalCb(collection[key], key);
1339        }
1340      }
1341    }
1342  };
1343
1344  //see http://jsperf.com/iterators/3
1345  //utilizing for in is way faster
1346  var _each = function _each(collection, cb) {
1347    _iterate(collection, cb, function (val, key) {
1348      cb(val, key);
1349    });
1350  };
1351
1352  return {
1353    each: _each,
1354    forEach: _each,
1355    every: _every,
1356    all: _all
1357  };
1358});
1359
1360'use strict';
1361
1362angular.module('ui-leaflet').factory('leafletLayerHelpers', function ($rootScope, $q, leafletLogger, leafletHelpers, leafletIterators) {
1363    var Helpers = leafletHelpers;
1364    var isString = leafletHelpers.isString;
1365    var isObject = leafletHelpers.isObject;
1366    var isArray = leafletHelpers.isArray;
1367    var isDefined = leafletHelpers.isDefined;
1368    var errorHeader = leafletHelpers.errorHeader;
1369    var $it = leafletIterators;
1370    var $log = leafletLogger;
1371
1372    var utfGridCreateLayer = function utfGridCreateLayer(params) {
1373        if (!Helpers.UTFGridPlugin.isLoaded()) {
1374            $log.error('[AngularJS - Leaflet] The UTFGrid plugin is not loaded.');
1375            return;
1376        }
1377        var utfgrid = new L.UtfGrid(params.url, params.pluginOptions);
1378
1379        var toSend = {
1380            model: params.$parent
1381        };
1382
1383        // TODO Use event manager
1384        utfgrid.on('mouseover', function (e) {
1385            angular.extend(toSend, {
1386                leafletEvent: e,
1387                leafletObject: e.target
1388            });
1389            $rootScope.$broadcast('leafletDirectiveMap.utfgridMouseover', toSend);
1390        });
1391
1392        utfgrid.on('mouseout', function (e) {
1393            angular.extend(toSend, {
1394                leafletEvent: e,
1395                leafletObject: e.target
1396            });
1397            $rootScope.$broadcast('leafletDirectiveMap.utfgridMouseout', toSend);
1398        });
1399
1400        utfgrid.on('click', function (e) {
1401            angular.extend(toSend, {
1402                leafletEvent: e,
1403                leafletObject: e.target
1404            });
1405            $rootScope.$broadcast('leafletDirectiveMap.utfgridClick', toSend);
1406        });
1407
1408        utfgrid.on('mousemove', function (e) {
1409            angular.extend(toSend, {
1410                leafletEvent: e,
1411                leafletObject: e.target
1412            });
1413            $rootScope.$broadcast('leafletDirectiveMap.utfgridMousemove', toSend);
1414        });
1415
1416        return utfgrid;
1417    };
1418
1419    var layerTypes = {
1420        xyz: {
1421            mustHaveUrl: true,
1422            createLayer: function createLayer(params) {
1423                return L.tileLayer(params.url, params.options);
1424            }
1425        },
1426        geoJSON: {
1427            mustHaveUrl: true,
1428            createLayer: function createLayer(params) {
1429                if (!Helpers.GeoJSONPlugin.isLoaded()) {
1430                    return;
1431                }
1432                return new L.TileLayer.GeoJSON(params.url, params.pluginOptions, params.options);
1433            }
1434        },
1435        geoJSONShape: {
1436            mustHaveUrl: false,
1437            createLayer: function createLayer(params) {
1438                return new L.GeoJSON(params.data, params.options);
1439            }
1440        },
1441        geoJSONAwesomeMarker: {
1442            mustHaveUrl: false,
1443            createLayer: function createLayer(params) {
1444                return new L.geoJson(params.data, {
1445                    pointToLayer: function pointToLayer(feature, latlng) {
1446                        return L.marker(latlng, { icon: L.AwesomeMarkers.icon(params.icon) });
1447                    }
1448                });
1449            }
1450        },
1451        geoJSONVectorMarker: {
1452            mustHaveUrl: false,
1453            createLayer: function createLayer(params) {
1454                return new L.geoJson(params.data, {
1455                    pointToLayer: function pointToLayer(feature, latlng) {
1456                        return L.marker(latlng, { icon: L.VectorMarkers.icon(params.icon) });
1457                    }
1458                });
1459            }
1460        },
1461        cartodbTiles: {
1462            mustHaveKey: true,
1463            createLayer: function createLayer(params) {
1464                var url = isDefined(params.url) ? params.url + '/' + params.user : '//' + params.user + '.cartodb.com';
1465                url += '/api/v1/map/' + params.key + '/{z}/{x}/{y}.png';
1466                return L.tileLayer(url, params.options);
1467            }
1468        },
1469        cartodbUTFGrid: {
1470            mustHaveKey: true,
1471            mustHaveLayer: true,
1472            createLayer: function createLayer(params) {
1473                var url = isDefined(params.url) ? params.url + '/' + params.user : '//' + params.user + '.cartodb.com';
1474                params.url = url + '/api/v1/map/' + params.key + '/' + params.layer + '/{z}/{x}/{y}.grid.json';
1475                return utfGridCreateLayer(params);
1476            }
1477        },
1478        cartodbInteractive: {
1479            mustHaveKey: true,
1480            mustHaveLayer: true,
1481            createLayer: function createLayer(params) {
1482                var url = isDefined(params.url) ? params.url + '/' + params.user : '//' + params.user + '.cartodb.com';
1483                var tilesURL = url + '/api/v1/map/' + params.key + '/{z}/{x}/{y}.png';
1484                var tileLayer = L.tileLayer(tilesURL, params.options);
1485                var layers = [tileLayer];
1486
1487                var addUtfLayer = function addUtfLayer(parent, params, layer) {
1488                    var paramsCopy = angular.copy(params);
1489                    paramsCopy.url = url + '/api/v1/map/' + paramsCopy.key + '/' + layer + '/{z}/{x}/{y}.grid.json';
1490                    parent.push(utfGridCreateLayer(paramsCopy));
1491                };
1492
1493                if (isArray(params.layer)) {
1494                    for (var i = 0; i < params.layer.length; i++) {
1495                        addUtfLayer(layers, params, params.layer[i]);
1496                    }
1497                } else {
1498                    addUtfLayer(layers, params, params.layer);
1499                }
1500                return L.layerGroup(layers);
1501            }
1502        },
1503        wms: {
1504            mustHaveUrl: true,
1505            createLayer: function createLayer(params) {
1506                return L.tileLayer.wms(params.url, params.options);
1507            }
1508        },
1509        wmts: {
1510            mustHaveUrl: true,
1511            createLayer: function createLayer(params) {
1512                return L.tileLayer.wmts(params.url, params.options);
1513            }
1514        },
1515        group: {
1516            mustHaveUrl: false,
1517            createLayer: function createLayer(params) {
1518                var lyrs = [];
1519                $it.each(params.options.layers, function (l) {
1520                    lyrs.push(_createLayer(l));
1521                });
1522                params.options.loadedDefer = function () {
1523                    var defers = [];
1524                    if (isDefined(params.options.layers)) {
1525                        for (var i = 0; i < params.options.layers.length; i++) {
1526                            var d = params.options.layers[i].layerOptions.loadedDefer;
1527                            if (isDefined(d)) {
1528                                defers.push(d);
1529                            }
1530                        }
1531                    }
1532                    return defers;
1533                };
1534                return L.layerGroup(lyrs);
1535            }
1536        },
1537        featureGroup: {
1538            mustHaveUrl: false,
1539            createLayer: function createLayer() {
1540                return L.featureGroup();
1541            }
1542        },
1543        markercluster: {
1544            mustHaveUrl: false,
1545            createLayer: function createLayer(params) {
1546                if (!Helpers.MarkerClusterPlugin.isLoaded()) {
1547                    $log.warn(errorHeader + ' The markercluster plugin is not loaded.');
1548                    return;
1549                }
1550                return new L.MarkerClusterGroup(params.options);
1551            }
1552        },
1553        imageOverlay: {
1554            mustHaveUrl: true,
1555            mustHaveBounds: true,
1556            createLayer: function createLayer(params) {
1557                return L.imageOverlay(params.url, params.bounds, params.options);
1558            }
1559        },
1560        iip: {
1561            mustHaveUrl: true,
1562            createLayer: function createLayer(params) {
1563                return L.tileLayer.iip(params.url, params.options);
1564            }
1565        },
1566
1567        // This "custom" type is used to accept every layer that user want to define himself.
1568        // We can wrap these custom layers like heatmap or yandex, but it means a lot of work/code to wrap the world,
1569        // so we let user to define their own layer outside the directive,
1570        // and pass it on "createLayer" result for next processes
1571        custom: {
1572            createLayer: function createLayer(params) {
1573                if (params.layer instanceof L.Class) {
1574                    return angular.copy(params.layer);
1575                } else {
1576                    $log.error('[AngularJS - Leaflet] A custom layer must be a leaflet Class');
1577                }
1578            }
1579        },
1580        cartodb: {
1581            mustHaveUrl: true,
1582            createLayer: function createLayer(params) {
1583                return cartodb.createLayer(params.map, params.url);
1584            }
1585        }
1586    };
1587
1588    function isValidLayerType(layerDefinition) {
1589        // Check if the baselayer has a valid type
1590        if (!isString(layerDefinition.type)) {
1591            $log.error('[AngularJS - Leaflet] A layer must have a valid type defined.');
1592            return false;
1593        }
1594
1595        if (Object.keys(layerTypes).indexOf(layerDefinition.type) === -1) {
1596            $log.error('[AngularJS - Leaflet] A layer must have a valid type: ' + Object.keys(layerTypes));
1597            return false;
1598        }
1599
1600        // Check if the layer must have an URL
1601        if (layerTypes[layerDefinition.type].mustHaveUrl && !isString(layerDefinition.url)) {
1602            $log.error('[AngularJS - Leaflet] A base layer must have an url');
1603            return false;
1604        }
1605
1606        if (layerTypes[layerDefinition.type].mustHaveData && !isDefined(layerDefinition.data)) {
1607            $log.error('[AngularJS - Leaflet] The base layer must have a "data" array attribute');
1608            return false;
1609        }
1610
1611        if (layerTypes[layerDefinition.type].mustHaveLayer && !isDefined(layerDefinition.layer)) {
1612            $log.error('[AngularJS - Leaflet] The type of layer ' + layerDefinition.type + ' must have an layer defined');
1613            return false;
1614        }
1615
1616        if (layerTypes[layerDefinition.type].mustHaveBounds && !isDefined(layerDefinition.bounds)) {
1617            $log.error('[AngularJS - Leaflet] The type of layer ' + layerDefinition.type + ' must have bounds defined');
1618            return false;
1619        }
1620
1621        if (layerTypes[layerDefinition.type].mustHaveKey && !isDefined(layerDefinition.key)) {
1622            $log.error('[AngularJS - Leaflet] The type of layer ' + layerDefinition.type + ' must have key defined');
1623            return false;
1624        }
1625        return true;
1626    }
1627
1628    function _createLayer(layerDefinition) {
1629        if (!isValidLayerType(layerDefinition)) {
1630            return;
1631        }
1632
1633        if (!isString(layerDefinition.name)) {
1634            $log.error('[AngularJS - Leaflet] A base layer must have a name');
1635            return;
1636        }
1637        if (!isObject(layerDefinition.layerParams)) {
1638            layerDefinition.layerParams = {};
1639        }
1640        if (!isObject(layerDefinition.layerOptions)) {
1641            layerDefinition.layerOptions = {};
1642        }
1643
1644        // Mix the layer specific parameters with the general Leaflet options. Although this is an overhead
1645        // the definition of a base layers is more 'clean' if the two types of parameters are differentiated
1646        for (var attrname in layerDefinition.layerParams) {
1647            layerDefinition.layerOptions[attrname] = layerDefinition.layerParams[attrname];
1648        }
1649
1650        var params = {
1651            url: layerDefinition.url,
1652            data: layerDefinition.data,
1653            options: layerDefinition.layerOptions,
1654            layer: layerDefinition.layer,
1655            icon: layerDefinition.icon,
1656            type: layerDefinition.layerType,
1657            bounds: layerDefinition.bounds,
1658            key: layerDefinition.key,
1659            apiKey: layerDefinition.apiKey,
1660            pluginOptions: layerDefinition.pluginOptions,
1661            user: layerDefinition.user,
1662            $parent: layerDefinition
1663        };
1664
1665        //TODO Add $watch to the layer properties
1666        return layerTypes[layerDefinition.type].createLayer(params);
1667    }
1668
1669    function safeAddLayer(map, layer) {
1670        if (layer && typeof layer.addTo === 'function') {
1671            layer.addTo(map);
1672        } else {
1673            map.addLayer(layer);
1674        }
1675    }
1676
1677    function safeRemoveLayer(map, layer, layerOptions) {
1678        if (isDefined(layerOptions) && isDefined(layerOptions.loadedDefer)) {
1679            if (angular.isFunction(layerOptions.loadedDefer)) {
1680                var defers = layerOptions.loadedDefer();
1681                $log.debug('Loaded Deferred', defers);
1682                var count = defers.length;
1683                if (count > 0) {
1684                    var resolve = function resolve() {
1685                        count--;
1686                        if (count === 0) {
1687                            map.removeLayer(layer);
1688                        }
1689                    };
1690
1691                    for (var i = 0; i < defers.length; i++) {
1692                        defers[i].promise.then(resolve);
1693                    }
1694                } else {
1695                    map.removeLayer(layer);
1696                }
1697            } else {
1698                layerOptions.loadedDefer.promise.then(function () {
1699                    map.removeLayer(layer);
1700                });
1701            }
1702        } else {
1703            map.removeLayer(layer);
1704        }
1705    }
1706
1707    var changeOpacityListener = function changeOpacityListener(op) {
1708        return function (ly) {
1709            if (isDefined(ly.setOpacity)) {
1710                ly.setOpacity(op);
1711            }
1712        };
1713    };
1714
1715    return {
1716        createLayer: _createLayer,
1717        layerTypes: layerTypes,
1718        safeAddLayer: safeAddLayer,
1719        safeRemoveLayer: safeRemoveLayer,
1720        changeOpacityListener: changeOpacityListener
1721    };
1722});
1723
1724'use strict';
1725
1726angular.module("ui-leaflet").factory('leafletLegendHelpers', function ($http, $q, $log, leafletHelpers) {
1727	var requestQueue = {},
1728	    isDefined = leafletHelpers.isDefined;
1729
1730	var _execNext = function _execNext(mapId) {
1731		var queue = requestQueue[mapId];
1732		var task = queue[0];
1733		$http(task.c).then(function (data) {
1734			queue.shift();
1735			task.d.resolve(data);
1736			if (queue.length > 0) {
1737				_execNext(mapId);
1738			}
1739		}, function (err) {
1740			queue.shift();
1741			task.d.reject(err);
1742			if (queue.length > 0) {
1743				_execNext(mapId);
1744			}
1745		});
1746	};
1747
1748	var _updateLegend = function _updateLegend(div, legendData, type, url) {
1749		div.innerHTML = '';
1750		if (legendData.error) {
1751			div.innerHTML += '<div class="info-title alert alert-danger">' + legendData.error.message + '</div>';
1752		} else {
1753			if (type === 'arcgis') {
1754				for (var i = 0; i < legendData.layers.length; i++) {
1755					var layer = legendData.layers[i];
1756					div.innerHTML += '<div class="info-title" data-layerid="' + layer.layerId + '">' + layer.layerName + '</div>';
1757					for (var j = 0; j < layer.legend.length; j++) {
1758						var leg = layer.legend[j];
1759						div.innerHTML += '<div class="inline" data-layerid="' + layer.layerId + '"><img src="data:' + leg.contentType + ';base64,' + leg.imageData + '" /></div>' + '<div class="info-label" data-layerid="' + layer.layerId + '">' + leg.label + '</div>';
1760					}
1761				}
1762			} else if (type === 'image') {
1763				div.innerHTML = '<img src="' + url + '"/>';
1764			}
1765		}
1766	};
1767
1768	var _getOnAddLegend = function _getOnAddLegend(legendData, legendClass, type, url) {
1769		return function () /*map*/{
1770			var div = L.DomUtil.create('div', legendClass);
1771
1772			if (!L.Browser.touch) {
1773				L.DomEvent.disableClickPropagation(div);
1774				L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
1775			} else {
1776				L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
1777			}
1778			_updateLegend(div, legendData, type, url);
1779			return div;
1780		};
1781	};
1782
1783	var _getOnAddArrayLegend = function _getOnAddArrayLegend(legend, legendClass) {
1784		return function () /*map*/{
1785			var div = L.DomUtil.create('div', legendClass);
1786			for (var i = 0; i < legend.colors.length; i++) {
1787				div.innerHTML += '<div class="outline"><i style="background:' + legend.colors[i] + '"></i></div>' + '<div class="info-label">' + legend.labels[i] + '</div>';
1788			}
1789			if (!L.Browser.touch) {
1790				L.DomEvent.disableClickPropagation(div);
1791				L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
1792			} else {
1793				L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
1794			}
1795			return div;
1796		};
1797	};
1798
1799	return {
1800		getOnAddLegend: _getOnAddLegend,
1801		getOnAddArrayLegend: _getOnAddArrayLegend,
1802		updateLegend: _updateLegend,
1803		addLegendURL: function addLegendURL(mapId, config) {
1804			var d = $q.defer();
1805			if (!isDefined(requestQueue[mapId])) {
1806				requestQueue[mapId] = [];
1807			}
1808			requestQueue[mapId].push({ c: config, d: d });
1809			if (requestQueue[mapId].length === 1) {
1810				_execNext(mapId);
1811			}
1812			return d.promise;
1813		}
1814	};
1815});
1816
1817'use strict';
1818
1819angular.module('ui-leaflet').factory('leafletMapDefaults', function ($q, leafletHelpers) {
1820    function _getDefaults() {
1821        return {
1822            keyboard: true,
1823            dragging: true,
1824            worldCopyJump: false,
1825            doubleClickZoom: true,
1826            scrollWheelZoom: true,
1827            tap: true,
1828            touchZoom: true,
1829            zoomControl: true,
1830            zoomsliderControl: false,
1831            zoomControlPosition: 'topleft',
1832            attributionControl: true,
1833            controls: {
1834                layers: {
1835                    visible: true,
1836                    position: 'topright',
1837                    collapsed: true
1838                }
1839            },
1840            nominatim: {
1841                server: ' http://nominatim.openstreetmap.org/search'
1842            },
1843            crs: L.CRS.EPSG3857,
1844            tileLayer: '//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
1845            tileLayerOptions: {
1846                attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
1847            },
1848            path: {
1849                weight: 10,
1850                opacity: 1,
1851                color: '#0000ff'
1852            },
1853            center: {
1854                lat: 0,
1855                lng: 0,
1856                zoom: 1
1857            },
1858            trackResize: true
1859        };
1860    }
1861
1862    var isDefined = leafletHelpers.isDefined,
1863        isObject = leafletHelpers.isObject,
1864        obtainEffectiveMapId = leafletHelpers.obtainEffectiveMapId,
1865        defaults = {};
1866
1867    // Get the _defaults dictionary, and override the properties defined by the user
1868    return {
1869        reset: function reset() {
1870            defaults = {};
1871        },
1872        getDefaults: function getDefaults(scopeId) {
1873            var mapId = obtainEffectiveMapId(defaults, scopeId);
1874            return defaults[mapId];
1875        },
1876
1877        getMapCreationDefaults: function getMapCreationDefaults(scopeId) {
1878            var mapId = obtainEffectiveMapId(defaults, scopeId);
1879            var d = defaults[mapId];
1880
1881            var mapDefaults = {
1882                maxZoom: d.maxZoom,
1883                keyboard: d.keyboard,
1884                dragging: d.dragging,
1885                zoomControl: d.zoomControl,
1886                doubleClickZoom: d.doubleClickZoom,
1887                scrollWheelZoom: d.scrollWheelZoom,
1888                tap: d.tap,
1889                touchZoom: d.touchZoom,
1890                attributionControl: d.attributionControl,
1891                worldCopyJump: d.worldCopyJump,
1892                crs: d.crs,
1893                trackResize: d.trackResize
1894            };
1895
1896            if (isDefined(d.minZoom)) {
1897                mapDefaults.minZoom = d.minZoom;
1898            }
1899
1900            if (isDefined(d.zoomAnimation)) {
1901                mapDefaults.zoomAnimation = d.zoomAnimation;
1902            }
1903
1904            if (isDefined(d.fadeAnimation)) {
1905                mapDefaults.fadeAnimation = d.fadeAnimation;
1906            }
1907
1908            if (isDefined(d.markerZoomAnimation)) {
1909                mapDefaults.markerZoomAnimation = d.markerZoomAnimation;
1910            }
1911
1912            if (d.map) {
1913                for (var option in d.map) {
1914                    mapDefaults[option] = d.map[option];
1915                }
1916            }
1917
1918            return mapDefaults;
1919        },
1920
1921        setDefaults: function setDefaults(userDefaults, scopeId) {
1922            var newDefaults = _getDefaults();
1923
1924            if (isDefined(userDefaults)) {
1925                newDefaults.doubleClickZoom = isDefined(userDefaults.doubleClickZoom) ? userDefaults.doubleClickZoom : newDefaults.doubleClickZoom;
1926                newDefaults.scrollWheelZoom = isDefined(userDefaults.scrollWheelZoom) ? userDefaults.scrollWheelZoom : newDefaults.doubleClickZoom;
1927                newDefaults.tap = isDefined(userDefaults.tap) ? userDefaults.tap : newDefaults.tap;
1928                newDefaults.touchZoom = isDefined(userDefaults.touchZoom) ? userDefaults.touchZoom : newDefaults.doubleClickZoom;
1929                newDefaults.zoomControl = isDefined(userDefaults.zoomControl) ? userDefaults.zoomControl : newDefaults.zoomControl;
1930                newDefaults.zoomsliderControl = isDefined(userDefaults.zoomsliderControl) ? userDefaults.zoomsliderControl : newDefaults.zoomsliderControl;
1931                newDefaults.attributionControl = isDefined(userDefaults.attributionControl) ? userDefaults.attributionControl : newDefaults.attributionControl;
1932                newDefaults.tileLayer = isDefined(userDefaults.tileLayer) ? userDefaults.tileLayer : newDefaults.tileLayer;
1933                newDefaults.zoomControlPosition = isDefined(userDefaults.zoomControlPosition) ? userDefaults.zoomControlPosition : newDefaults.zoomControlPosition;
1934                newDefaults.keyboard = isDefined(userDefaults.keyboard) ? userDefaults.keyboard : newDefaults.keyboard;
1935                newDefaults.dragging = isDefined(userDefaults.dragging) ? userDefaults.dragging : newDefaults.dragging;
1936                newDefaults.trackResize = isDefined(userDefaults.trackResize) ? userDefaults.trackResize : newDefaults.trackResize;
1937
1938                if (isDefined(userDefaults.controls)) {
1939                    angular.extend(newDefaults.controls, userDefaults.controls);
1940                }
1941
1942                if (isObject(userDefaults.crs)) {
1943                    newDefaults.crs = userDefaults.crs;
1944                } else if (isDefined(L.CRS[userDefaults.crs])) {
1945                    newDefaults.crs = L.CRS[userDefaults.crs];
1946                }
1947
1948                if (isDefined(userDefaults.center)) {
1949                    angular.copy(userDefaults.center, newDefaults.center);
1950                }
1951
1952                if (isDefined(userDefaults.tileLayerOptions)) {
1953                    angular.copy(userDefaults.tileLayerOptions, newDefaults.tileLayerOptions);
1954                }
1955
1956                if (isDefined(userDefaults.maxZoom)) {
1957                    newDefaults.maxZoom = userDefaults.maxZoom;
1958                }
1959
1960                if (isDefined(userDefaults.minZoom)) {
1961                    newDefaults.minZoom = userDefaults.minZoom;
1962                }
1963
1964                if (isDefined(userDefaults.zoomAnimation)) {
1965                    newDefaults.zoomAnimation = userDefaults.zoomAnimation;
1966                }
1967
1968                if (isDefined(userDefaults.fadeAnimation)) {
1969                    newDefaults.fadeAnimation = userDefaults.fadeAnimation;
1970                }
1971
1972                if (isDefined(userDefaults.markerZoomAnimation)) {
1973                    newDefaults.markerZoomAnimation = userDefaults.markerZoomAnimation;
1974                }
1975
1976                if (isDefined(userDefaults.worldCopyJump)) {
1977                    newDefaults.worldCopyJump = userDefaults.worldCopyJump;
1978                }
1979
1980                if (isDefined(userDefaults.map)) {
1981                    newDefaults.map = userDefaults.map;
1982                }
1983
1984                if (isDefined(userDefaults.path)) {
1985                    newDefaults.path = userDefaults.path;
1986                }
1987            }
1988
1989            var mapId = obtainEffectiveMapId(defaults, scopeId);
1990            defaults[mapId] = newDefaults;
1991            return newDefaults;
1992        }
1993    };
1994});
1995
1996'use strict';
1997
1998angular.module('ui-leaflet').service('leafletMarkersHelpers', function ($rootScope, $timeout, leafletHelpers, leafletLogger, $compile, leafletGeoJsonHelpers, leafletWatchHelpers) {
1999    var isDefined = leafletHelpers.isDefined,
2000        defaultTo = leafletHelpers.defaultTo,
2001        MarkerClusterPlugin = leafletHelpers.MarkerClusterPlugin,
2002        AwesomeMarkersPlugin = leafletHelpers.AwesomeMarkersPlugin,
2003        VectorMarkersPlugin = leafletHelpers.VectorMarkersPlugin,
2004        MakiMarkersPlugin = leafletHelpers.MakiMarkersPlugin,
2005        ExtraMarkersPlugin = leafletHelpers.ExtraMarkersPlugin,
2006        DomMarkersPlugin = leafletHelpers.DomMarkersPlugin,
2007        safeApply = leafletHelpers.safeApply,
2008        Helpers = leafletHelpers,
2009        isString = leafletHelpers.isString,
2010        isNumber = leafletHelpers.isNumber,
2011        isObject = leafletHelpers.isObject,
2012        groups = {},
2013        geoHlp = leafletGeoJsonHelpers,
2014        errorHeader = leafletHelpers.errorHeader,
2015        maybeWatch = leafletWatchHelpers.maybeWatch,
2016        $log = leafletLogger;
2017
2018    var _string = function _string(marker) {
2019        //this exists since JSON.stringify barfs on cyclic
2020        var retStr = '';
2021        ['_icon', '_latlng', '_leaflet_id', '_map', '_shadow'].forEach(function (prop) {
2022            retStr += prop + ': ' + defaultTo(marker[prop], 'undefined') + ' \n';
2023        });
2024        return '[leafletMarker] : \n' + retStr;
2025    };
2026    var _log = function _log(marker, useConsole) {
2027        var logger = useConsole ? console : $log;
2028        logger.debug(_string(marker));
2029    };
2030
2031    var existDomContainer = function existDomContainer(groupName) {
2032        return angular.element(groups[groupName]._map._container).parent().length > 0;
2033    };
2034
2035    var createLeafletIcon = function createLeafletIcon(iconData) {
2036        if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'awesomeMarker') {
2037            if (!AwesomeMarkersPlugin.isLoaded()) {
2038                $log.error(errorHeader + ' The AwesomeMarkers Plugin is not loaded.');
2039            }
2040
2041            return new L.AwesomeMarkers.icon(iconData);
2042        }
2043
2044        if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'vectorMarker') {
2045            if (!VectorMarkersPlugin.isLoaded()) {
2046                $log.error(errorHeader + ' The VectorMarkers Plugin is not loaded.');
2047            }
2048
2049            return new L.VectorMarkers.icon(iconData);
2050        }
2051
2052        if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'makiMarker') {
2053            if (!MakiMarkersPlugin.isLoaded()) {
2054                $log.error(errorHeader + 'The MakiMarkers Plugin is not loaded.');
2055            }
2056
2057            return new L.MakiMarkers.icon(iconData);
2058        }
2059
2060        if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'extraMarker') {
2061            if (!ExtraMarkersPlugin.isLoaded()) {
2062                $log.error(errorHeader + 'The ExtraMarkers Plugin is not loaded.');
2063            }
2064            return new L.ExtraMarkers.icon(iconData);
2065        }
2066
2067        if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'div') {
2068            return new L.divIcon(iconData);
2069        }
2070
2071        if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'dom') {
2072            if (!DomMarkersPlugin.isLoaded()) {
2073                $log.error(errorHeader + 'The DomMarkers Plugin is not loaded.');
2074            }
2075            var markerScope = angular.isFunction(iconData.getMarkerScope) ? iconData.getMarkerScope().$new() : $rootScope,
2076                template = $compile(iconData.template)(markerScope),
2077                iconDataCopy = angular.copy(iconData);
2078            iconDataCopy.ngElement = template;
2079            iconDataCopy.element = template[0];
2080            if (angular.isFunction(iconData.getMarkerScope)) iconDataCopy.scope = markerScope;
2081            return new L.DomMarkers.icon(iconDataCopy);
2082        }
2083
2084        // allow for any custom icon to be used... assumes the icon has already been initialized
2085        if (isDefined(iconData) && isDefined(iconData.type) && iconData.type === 'icon') {
2086            return iconData.icon;
2087        }
2088
2089        var base64icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAGmklEQVRYw7VXeUyTZxjvNnfELFuyIzOabermMZEeQC/OclkO49CpOHXOLJl/CAURuYbQi3KLgEhbrhZ1aDwmaoGqKII6odATmH/scDFbdC7LvFqOCc+e95s2VG50X/LLm/f4/Z7neY/ne18aANCmAr5E/xZf1uDOkTcGcWR6hl9247tT5U7Y6SNvWsKT63P58qbfeLJG8M5qcgTknrvvrdDbsT7Ml+tv82X6vVxJE33aRmgSyYtcWVMqX97Yv2JvW39UhRE2HuyBL+t+gK1116ly06EeWFNlAmHxlQE0OMiV6mQCScusKRlhS3QLeVJdl1+23h5dY4FNB3thrbYboqptEFlphTC1hSpJnbRvxP4NWgsE5Jyz86QNNi/5qSUTGuFk1gu54tN9wuK2wc3o+Wc13RCmsoBwEqzGcZsxsvCSy/9wJKf7UWf1mEY8JWfewc67UUoDbDjQC+FqK4QqLVMGGR9d2wurKzqBk3nqIT/9zLxRRjgZ9bqQgub+DdoeCC03Q8j+0QhFhBHR/eP3U/zCln7Uu+hihJ1+bBNffLIvmkyP0gpBZWYXhKussK6mBz5HT6M1Nqpcp+mBCPXosYQfrekGvrjewd59/GvKCE7TbK/04/ZV5QZYVWmDwH1mF3xa2Q3ra3DBC5vBT1oP7PTj4C0+CcL8c7C2CtejqhuCnuIQHaKHzvcRfZpnylFfXsYJx3pNLwhKzRAwAhEqG0SpusBHfAKkxw3w4627MPhoCH798z7s0ZnBJ/MEJbZSbXPhER2ih7p2ok/zSj2cEJDd4CAe+5WYnBCgR2uruyEw6zRoW6/DWJ/OeAP8pd/BGtzOZKpG8oke0SX6GMmRk6GFlyAc59K32OTEinILRJRchah8HQwND8N435Z9Z0FY1EqtxUg+0SO6RJ/mmXz4VuS+DpxXC3gXmZwIL7dBSH4zKE50wESf8qwVgrP1EIlTO5JP9Igu0aexdh28F1lmAEGJGfh7jE6ElyM5Rw/FDcYJjWhbeiBYoYNIpc2FT/SILivp0F1ipDWk4BIEo2VuodEJUifhbiltnNBIXPUFCMpthtAyqws/BPlEF/VbaIxErdxPphsU7rcCp8DohC+GvBIPJS/tW2jtvTmmAeuNO8BNOYQeG8G/2OzCJ3q+soYB5i6NhMaKr17FSal7GIHheuV3uSCY8qYVuEm1cOzqdWr7ku/R0BDoTT+DT+ohCM6/CCvKLKO4RI+dXPeAuaMqksaKrZ7L3FE5FIFbkIceeOZ2OcHO6wIhTkNo0ffgjRGxEqogXHYUPHfWAC/lADpwGcLRY3aeK4/oRGCKYcZXPVoeX/kelVYY8dUGf8V5EBRbgJXT5QIPhP9ePJi428JKOiEYhYXFBqou2Guh+p/mEB1/RfMw6rY7cxcjTrneI1FrDyuzUSRm9miwEJx8E/gUmqlyvHGkneiwErR21F3tNOK5Tf0yXaT+O7DgCvALTUBXdM4YhC/IawPU+2PduqMvuaR6eoxSwUk75ggqsYJ7VicsnwGIkZBSXKOUww73WGXyqP+J2/b9c+gi1YAg/xpwck3gJuucNrh5JvDPvQr0WFXf0piyt8f8/WI0hV4pRxxkQZdJDfDJNOAmM0Ag8jyT6hz0WGXWuP94Yh2jcfjmXAGvHCMslRimDHYuHuDsy2QtHuIavznhbYURq5R57KpzBBRZKPJi8eQg48h4j8SDdowifdIrEVdU+gbO6QNvRRt4ZBthUaZhUnjlYObNagV3keoeru3rU7rcuceqU1mJBxy+BWZYlNEBH+0eH4vRiB+OYybU2hnblYlTvkHinM4m54YnxSyaZYSF6R3jwgP7udKLGIX6r/lbNa9N6y5MFynjWDtrHd75ZvTYAPO/6RgF0k76mQla3FGq7dO+cH8sKn0Vo7nDllwAhqwLPkxrHwWmHJOo+AKJ4rab5OgrM7rVu8eWb2Pu0Dh4eDgXoOfvp7Y7QeqknRmvcTBEyq9m/HQQSCSz6LHq3z0yzsNySRfMS253wl2KyRDbcZPcfJKjZmSEOjcxyi+Y8dUOtsIEH6R2wNykdqrkYJ0RV92H0W58pkfQk7cKevsLK10Py8SdMGfXNXATY+pPbyJR/ET6n9nIfztNtZYRV9XniQu9IA2vOVgy4ir7GCLVmmd+zjkH0eAF9Po6K61pmCXHxU5rHMYd1ftc3owjwRSVRzLjKvqZEty6cRUD7jGqiOdu5HG6MdHjNcNYGqfDm5YRzLBBCCDl/2bk8a8gdbqcfwECu62Fg/HrggAAAABJRU5ErkJggg==";
2090        var base64shadow = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAApCAYAAACoYAD2AAAC5ElEQVRYw+2YW4/TMBCF45S0S1luXZCABy5CgLQgwf//S4BYBLTdJLax0fFqmB07nnQfEGqkIydpVH85M+NLjPe++dcPc4Q8Qh4hj5D/AaQJx6H/4TMwB0PeBNwU7EGQAmAtsNfAzoZkgIa0ZgLMa4Aj6CxIAsjhjOCoL5z7Glg1JAOkaicgvQBXuncwJAWjksLtBTWZe04CnYRktUGdilALppZBOgHGZcBzL6OClABvMSVIzyBjazOgrvACf1ydC5mguqAVg6RhdkSWQFj2uxfaq/BrIZOLEWgZdALIDvcMcZLD8ZbLC9de4yR1sYMi4G20S4Q/PWeJYxTOZn5zJXANZHIxAd4JWhPIloTJZhzMQduM89WQ3MUVAE/RnhAXpTycqys3NZALOBbB7kFrgLesQl2h45Fcj8L1tTSohUwuxhy8H/Qg6K7gIs+3kkaigQCOcyEXCHN07wyQazhrmIulvKMQAwMcmLNqyCVyMAI+BuxSMeTk3OPikLY2J1uE+VHQk6ANrhds+tNARqBeaGc72cK550FP4WhXmFmcMGhTwAR1ifOe3EvPqIegFmF+C8gVy0OfAaWQPMR7gF1OQKqGoBjq90HPMP01BUjPOqGFksC4emE48tWQAH0YmvOgF3DST6xieJgHAWxPAHMuNhrImIdvoNOKNWIOcE+UXE0pYAnkX6uhWsgVXDxHdTfCmrEEmMB2zMFimLVOtiiajxiGWrbU52EeCdyOwPEQD8LqyPH9Ti2kgYMf4OhSKB7qYILbBv3CuVTJ11Y80oaseiMWOONc/Y7kJYe0xL2f0BaiFTxknHO5HaMGMublKwxFGzYdWsBF174H/QDknhTHmHHN39iWFnkZx8lPyM8WHfYELmlLKtgWNmFNzQcC1b47gJ4hL19i7o65dhH0Negbca8vONZoP7doIeOC9zXm8RjuL0Gf4d4OYaU5ljo3GYiqzrWQHfJxA6ALhDpVKv9qYeZA8eM3EhfPSCmpuD0AAAAASUVORK5CYII=";
2091
2092        if (!isDefined(iconData) || !isDefined(iconData.iconUrl)) {
2093            return new L.Icon.Default({
2094                iconUrl: base64icon,
2095                shadowUrl: base64shadow,
2096                iconSize: [25, 41],
2097                iconAnchor: [12, 41],
2098                popupAnchor: [1, -34],
2099                shadowSize: [41, 41]
2100            });
2101        }
2102
2103        return new L.Icon(iconData);
2104    };
2105
2106    var _resetMarkerGroup = function _resetMarkerGroup(groupName) {
2107        if (isDefined(groups[groupName])) {
2108            delete groups[groupName];
2109        }
2110    };
2111
2112    var _resetMarkerGroups = function _resetMarkerGroups() {
2113        groups = {};
2114    };
2115
2116    var _resetUnusedMarkerGroups = function _resetUnusedMarkerGroups() {
2117        for (var groupName in groups) {
2118            if (!existDomContainer(groupName)) {
2119                _resetMarkerGroup(groupName);
2120            }
2121        }
2122    };
2123
2124    var _cleanDomIcon = function _cleanDomIcon(marker) {
2125        if (marker.options.icon.options.ngElement) {
2126            marker.options.icon.options.ngElement.remove();
2127        }
2128        if (marker.options.icon.options.scope) {
2129            marker.options.icon.options.scope.$destroy();
2130        }
2131    };
2132
2133    var _deleteMarker = function _deleteMarker(marker, map, layers) {
2134        marker.closePopup();
2135
2136        // if it's a dom icon, clean it
2137        if (marker.options.icon && marker.options.icon.options && marker.options.icon.options.type === 'dom') {
2138            _cleanDomIcon(marker);
2139        }
2140
2141        // There is no easy way to know if a marker is added to a layer, so we search for it
2142        // if there are overlays
2143        if (isDefined(layers) && isDefined(layers.overlays)) {
2144            for (var key in layers.overlays) {
2145                if (layers.overlays[key] instanceof L.LayerGroup || layers.overlays[key] instanceof L.FeatureGroup) {
2146                    if (layers.overlays[key].hasLayer(marker)) {
2147                        layers.overlays[key].removeLayer(marker);
2148                        return;
2149                    }
2150                }
2151            }
2152        }
2153
2154        if (isDefined(groups)) {
2155            for (var groupKey in groups) {
2156                if (groups[groupKey].hasLayer(marker)) {
2157                    groups[groupKey].removeLayer(marker);
2158                }
2159            }
2160        }
2161
2162        if (map.hasLayer(marker)) {
2163            map.removeLayer(marker);
2164        }
2165    };
2166
2167    var adjustPopupPan = function adjustPopupPan(marker, map) {
2168        var containerHeight = marker._popup._container.offsetHeight,
2169            layerPos = new L.Point(marker._popup._containerLeft, -containerHeight - marker._popup._containerBottom),
2170            containerPos = map.layerPointToContainerPoint(layerPos);
2171        if (containerPos !== null) {
2172            marker._popup._adjustPan();
2173        }
2174    };
2175
2176    var compilePopup = function compilePopup(marker, markerScope) {
2177        $compile(marker._popup._contentNode)(markerScope);
2178    };
2179
2180    var updatePopup = function updatePopup(marker, markerScope, map) {
2181        //The innerText should be more than 1 once angular has compiled.
2182        //We need to keep trying until angular has compiled before we _updateLayout and _updatePosition
2183        //This should take care of any scenario , eg ngincludes, whatever.
2184        //Is there a better way to check for this?
2185        var innerText = marker._popup._contentNode.innerText || marker._popup._contentNode.textContent;
2186        if (innerText.length < 1) {
2187            $timeout(function () {
2188                updatePopup(marker, markerScope, map);
2189            });
2190        }
2191
2192        //cause a reflow - this is also very important - if we don't do this then the widths are from before $compile
2193        var reflow = marker._popup._contentNode.offsetWidth;
2194
2195        marker._popup._updateLayout();
2196        marker._popup._updatePosition();
2197
2198        if (marker._popup.options.autoPan) {
2199            adjustPopupPan(marker, map);
2200        }
2201
2202        //using / returning reflow so jshint doesn't moan
2203        return reflow;
2204    };
2205
2206    var _manageOpenPopup = function _manageOpenPopup(marker, markerData, map) {
2207        // The marker may provide a scope returning function used to compile the message
2208        // default to $rootScope otherwise
2209        var markerScope = angular.isFunction(markerData.getMessageScope) ? markerData.getMessageScope() : $rootScope,
2210            compileMessage = isDefined(markerData.compileMessage) ? markerData.compileMessage : true;
2211
2212        if (compileMessage) {
2213            if (!isDefined(marker._popup) || !isDefined(marker._popup._contentNode)) {
2214                $log.error(errorHeader + 'Popup is invalid or does not have any content.');
2215                return false;
2216            }
2217
2218            compilePopup(marker, markerScope);
2219            updatePopup(marker, markerData, map);
2220        }
2221    };
2222
2223    var _manageOpenLabel = function _manageOpenLabel(marker, markerData) {
2224        var markerScope = angular.isFunction(markerData.getMessageScope) ? markerData.getMessageScope() : $rootScope,
2225            labelScope = angular.isFunction(markerData.getLabelScope) ? markerData.getLabelScope() : markerScope,
2226            compileMessage = isDefined(markerData.compileMessage) ? markerData.compileMessage : true;
2227
2228        if (Helpers.LabelPlugin.isLoaded() && isDefined(markerData.label)) {
2229            if (isDefined(markerData.label.options) && markerData.label.options.noHide === true) {
2230                marker.showLabel();
2231            }
2232            if (compileMessage && isDefined(marker.label)) {
2233                $compile(marker.label._container)(labelScope);
2234            }
2235        }
2236    };
2237
2238    var _updateMarker = function _updateMarker(markerData, oldMarkerData, marker, name, leafletScope, layers, map) {
2239        if (!isDefined(oldMarkerData)) {
2240            return;
2241        }
2242
2243        // Update the lat-lng property (always present in marker properties)
2244        if (!geoHlp.validateCoords(markerData)) {
2245            $log.warn('There are problems with lat-lng data, please verify your marker model');
2246            _deleteMarker(marker, map, layers);
2247            return;
2248        }
2249
2250        // watch is being initialized if old and new object is the same
2251        var isInitializing = markerData === oldMarkerData;
2252
2253        // Update marker rotation
2254        if (isDefined(markerData.iconAngle) && oldMarkerData.iconAngle !== markerData.iconAngle) {
2255            marker.setIconAngle(markerData.iconAngle);
2256        }
2257
2258        // It is possible that the layer has been removed or the layer marker does not exist
2259        // Update the layer group if present or move it to the map if not
2260        if (!isString(markerData.layer)) {
2261            // There is no layer information, we move the marker to the map if it was in a layer group
2262            if (isString(oldMarkerData.layer)) {
2263                // Remove from the layer group that is supposed to be
2264                if (isDefined(layers.overlays[oldMarkerData.layer]) && layers.overlays[oldMarkerData.layer].hasLayer(marker)) {
2265                    layers.overlays[oldMarkerData.layer].removeLayer(marker);
2266                    marker.closePopup();
2267                }
2268                // Test if it is not on the map and add it
2269                if (!map.hasLayer(marker)) {
2270                    map.addLayer(marker);
2271                }
2272            }
2273        }
2274
2275        if ((isNumber(markerData.opacity) || isNumber(parseFloat(markerData.opacity))) && markerData.opacity !== oldMarkerData.opacity) {
2276            // There was a different opacity so we update it
2277            marker.setOpacity(markerData.opacity);
2278        }
2279
2280        if (isString(markerData.layer) && oldMarkerData.layer !== markerData.layer) {
2281            // If it was on a layer group we have to remove it
2282            if (isString(oldMarkerData.layer) && isDefined(layers.overlays[oldMarkerData.layer]) && layers.overlays[oldMarkerData.layer].hasLayer(marker)) {
2283                layers.overlays[oldMarkerData.layer].removeLayer(marker);
2284            }
2285            marker.closePopup();
2286
2287            // Remove it from the map in case the new layer is hidden or there is an error in the new layer
2288            if (map.hasLayer(marker)) {
2289                map.removeLayer(marker);
2290            }
2291
2292            // The markerData.layer is defined so we add the marker to the layer if it is different from the old data
2293            if (!isDefined(layers.overlays[markerData.layer])) {
2294                $log.error(errorHeader + 'You must use a name of an existing layer');
2295                return;
2296            }
2297            // Is a group layer?
2298            var layerGroup = layers.overlays[markerData.layer];
2299            if (!(layerGroup instanceof L.LayerGroup || layerGroup instanceof L.FeatureGroup)) {
2300                $log.error(errorHeader + 'A marker can only be added to a layer of type "group" or "featureGroup"');
2301                return;
2302            }
2303            // The marker goes to a correct layer group, so first of all we add it
2304            layerGroup.addLayer(marker);
2305            // The marker is automatically added to the map depending on the visibility
2306            // of the layer, so we only have to open the popup if the marker is in the map
2307            if (map.hasLayer(marker) && markerData.focus === true) {
2308                marker.openPopup();
2309            }
2310        }
2311
2312        // Update the draggable property
2313        if (markerData.draggable !== true && oldMarkerData.draggable === true && isDefined(marker.dragging)) {
2314            marker.dragging.disable();
2315        }
2316
2317        if (markerData.draggable === true && oldMarkerData.draggable !== true) {
2318            // The markerData.draggable property must be true so we update if there wasn't a previous value or it wasn't true
2319            if (marker.dragging) {
2320                marker.dragging.enable();
2321            } else {
2322                if (L.Handler.MarkerDrag) {
2323                    marker.dragging = new L.Handler.MarkerDrag(marker);
2324                    marker.options.draggable = true;
2325                    marker.dragging.enable();
2326                }
2327            }
2328        }
2329
2330        // Update the icon property
2331        if (!isObject(markerData.icon)) {
2332            // If there is no icon property or it's not an object
2333            if (isObject(oldMarkerData.icon)) {
2334                if (oldMarkerData.icon.type === 'dom') {
2335                    // clean previous icon if it's a dom one
2336                    _cleanDomIcon(marker);
2337                }
2338                // If there was an icon before restore to the default
2339                marker.setIcon(createLeafletIcon());
2340                marker.closePopup();
2341                marker.unbindPopup();
2342                if (isString(markerData.message)) {
2343                    marker.bindPopup(markerData.message, markerData.popupOptions);
2344                }
2345            }
2346        }
2347
2348        if (isObject(markerData.icon) && isObject(oldMarkerData.icon) && !angular.equals(markerData.icon, oldMarkerData.icon)) {
2349            var dragG = false;
2350            if (marker.dragging) {
2351                dragG = marker.dragging.enabled();
2352            }
2353            if (oldMarkerData.icon.type === 'dom') {
2354                // clean previous icon if it's a dom one
2355                _cleanDomIcon(marker);
2356            }
2357            marker.setIcon(createLeafletIcon(markerData.icon));
2358            if (dragG) {
2359                marker.dragging.enable();
2360            }
2361            marker.closePopup();
2362            marker.unbindPopup();
2363            if (isString(markerData.message)) {
2364                marker.bindPopup(markerData.message, markerData.popupOptions);
2365                // if marker has been already focused, reopen popup
2366                if (map.hasLayer(marker) && markerData.focus === true) {
2367                    marker.openPopup();
2368                }
2369            }
2370        }
2371
2372        // Update the Popup message property
2373        if (!isString(markerData.message) && isString(oldMarkerData.message)) {
2374            marker.closePopup();
2375            marker.unbindPopup();
2376        }
2377
2378        // Update the label content or bind a new label if the old one has been removed.
2379        if (Helpers.LabelPlugin.isLoaded()) {
2380            if (isDefined(markerData.label) && isDefined(markerData.label.message)) {
2381                if ('label' in oldMarkerData && 'message' in oldMarkerData.label && !angular.equals(markerData.label.message, oldMarkerData.label.message)) {
2382                    marker.updateLabelContent(markerData.label.message);
2383                } else if (!angular.isFunction(marker.getLabel) || angular.isFunction(marker.getLabel) && !isDefined(marker.getLabel())) {
2384                    marker.bindLabel(markerData.label.message, markerData.label.options);
2385                    _manageOpenLabel(marker, markerData);
2386                } else {
2387                    _manageOpenLabel(marker, markerData);
2388                }
2389            } else if (!('label' in markerData && !('message' in markerData.label))) {
2390                if (angular.isFunction(marker.unbindLabel)) {
2391                    marker.unbindLabel();
2392                }
2393            }
2394        }
2395
2396        // There is some text in the popup, so we must show the text or update existing
2397        if (isString(markerData.message) && !isString(oldMarkerData.message)) {
2398            // There was no message before so we create it
2399            marker.bindPopup(markerData.message, markerData.popupOptions);
2400        }
2401
2402        if (isString(markerData.message) && isString(oldMarkerData.message) && markerData.message !== oldMarkerData.message) {
2403            // There was a different previous message so we update it
2404            marker.setPopupContent(markerData.message);
2405        }
2406
2407        // Update the focus property
2408        var updatedFocus = false;
2409        if (markerData.focus !== true && oldMarkerData.focus === true) {
2410            // If there was a focus property and was true we turn it off
2411            marker.closePopup();
2412            updatedFocus = true;
2413        }
2414
2415        // The markerData.focus property must be true so we update if there wasn't a previous value or it wasn't true
2416        if (markerData.focus === true && (!isDefined(oldMarkerData.focus) || oldMarkerData.focus === false) || isInitializing && markerData.focus === true) {
2417            // Reopen the popup when focus is still true
2418            marker.openPopup();
2419            updatedFocus = true;
2420        }
2421
2422        // zIndexOffset adjustment
2423        if (oldMarkerData.zIndexOffset !== markerData.zIndexOffset) {
2424            marker.setZIndexOffset(markerData.zIndexOffset);
2425        }
2426
2427        var markerLatLng = marker.getLatLng();
2428        var isCluster = isString(markerData.layer) && Helpers.MarkerClusterPlugin.is(layers.overlays[markerData.layer]);
2429        // If the marker is in a cluster it has to be removed and added to the layer when the location is changed
2430        if (isCluster) {
2431            // The focus has changed even by a user click or programatically
2432            if (updatedFocus) {
2433                // We only have to update the location if it was changed programatically, because it was
2434                // changed by a user drag the marker data has already been updated by the internal event
2435                // listened by the directive
2436                if (markerData.lat !== oldMarkerData.lat || markerData.lng !== oldMarkerData.lng) {
2437                    layers.overlays[markerData.layer].removeLayer(marker);
2438                    marker.setLatLng([markerData.lat, markerData.lng]);
2439                    layers.overlays[markerData.layer].addLayer(marker);
2440                }
2441            } else {
2442                // The marker has possibly moved. It can be moved by a user drag (marker location and data are equal but old
2443                // data is diferent) or programatically (marker location and data are diferent)
2444                if (markerLatLng.lat !== markerData.lat || markerLatLng.lng !== markerData.lng) {
2445                    // The marker was moved by a user drag
2446                    layers.overlays[markerData.layer].removeLayer(marker);
2447                    marker.setLatLng([markerData.lat, markerData.lng]);
2448                    layers.overlays[markerData.layer].addLayer(marker);
2449                } else if (markerData.lat !== oldMarkerData.lat || markerData.lng !== oldMarkerData.lng) {
2450                    // The marker was moved programatically
2451                    layers.overlays[markerData.layer].removeLayer(marker);
2452                    marker.setLatLng([markerData.lat, markerData.lng]);
2453                    layers.overlays[markerData.layer].addLayer(marker);
2454                } else if (isObject(markerData.icon) && isObject(oldMarkerData.icon) && !angular.equals(markerData.icon, oldMarkerData.icon)) {
2455                    layers.overlays[markerData.layer].removeLayer(marker);
2456                    layers.overlays[markerData.layer].addLayer(marker);
2457                }
2458            }
2459        } else if (markerLatLng.lat !== markerData.lat || markerLatLng.lng !== markerData.lng) {
2460            marker.setLatLng([markerData.lat, markerData.lng]);
2461        }
2462    };
2463
2464    var _getLayerModels = function _getLayerModels(models, layerName) {
2465        if (!isDefined(models)) return;
2466        if (layerName) return models[layerName];
2467        return models;
2468    };
2469
2470    var _getModelFromModels = function _getModelFromModels(models, id, layerName) {
2471        if (!isDefined(models)) return;
2472        if (!id) {
2473            $log.error(errorHeader + 'marker id missing in getMarker');
2474            return;
2475        }
2476        if (layerName) return models[layerName][id];
2477
2478        return models[id];
2479    };
2480    return {
2481        resetMarkerGroup: _resetMarkerGroup,
2482
2483        resetMarkerGroups: _resetMarkerGroups,
2484
2485        resetUnusedMarkerGroups: _resetUnusedMarkerGroups,
2486
2487        deleteMarker: _deleteMarker,
2488
2489        manageOpenPopup: _manageOpenPopup,
2490
2491        manageOpenLabel: _manageOpenLabel,
2492
2493        createMarker: function createMarker(markerData) {
2494            if (!isDefined(markerData) || !geoHlp.validateCoords(markerData)) {
2495                $log.error(errorHeader + 'The marker definition is not valid.');
2496                return;
2497            }
2498            var coords = geoHlp.getCoords(markerData);
2499
2500            if (!isDefined(coords)) {
2501                $log.error(errorHeader + 'Unable to get coordinates from markerData.');
2502                return;
2503            }
2504
2505            var markerOptions = {
2506                icon: createLeafletIcon(markerData.icon),
2507                title: isDefined(markerData.title) ? markerData.title : '',
2508                draggable: isDefined(markerData.draggable) ? markerData.draggable : false,
2509                clickable: isDefined(markerData.clickable) ? markerData.clickable : true,
2510                riseOnHover: isDefined(markerData.riseOnHover) ? markerData.riseOnHover : false,
2511                zIndexOffset: isDefined(markerData.zIndexOffset) ? markerData.zIndexOffset : 0,
2512                iconAngle: isDefined(markerData.iconAngle) ? markerData.iconAngle : 0
2513            };
2514            // Add any other options not added above to markerOptions
2515            for (var markerDatum in markerData) {
2516                if (markerData.hasOwnProperty(markerDatum) && !markerOptions.hasOwnProperty(markerDatum)) {
2517                    markerOptions[markerDatum] = markerData[markerDatum];
2518                }
2519            }
2520
2521            var marker = new L.marker(coords, markerOptions);
2522
2523            if (!isString(markerData.message)) {
2524                marker.unbindPopup();
2525            }
2526
2527            return marker;
2528        },
2529
2530        addMarkerToGroup: function addMarkerToGroup(marker, groupName, groupOptions, map) {
2531            if (!isString(groupName)) {
2532                $log.error(errorHeader + 'The marker group you have specified is invalid.');
2533                return;
2534            }
2535
2536            if (!MarkerClusterPlugin.isLoaded()) {
2537                $log.error(errorHeader + "The MarkerCluster plugin is not loaded.");
2538                return;
2539            }
2540            if (!isDefined(groups[groupName])) {
2541                groups[groupName] = new L.MarkerClusterGroup(groupOptions);
2542                map.addLayer(groups[groupName]);
2543            }
2544            groups[groupName].addLayer(marker);
2545        },
2546
2547        listenMarkerEvents: function listenMarkerEvents(marker, markerData, leafletScope, watchType, map) {
2548            marker.on("popupopen", function () /* event */{
2549                safeApply(leafletScope, function () {
2550                    if (isDefined(marker._popup) || isDefined(marker._popup._contentNode)) {
2551                        markerData.focus = true;
2552                        _manageOpenPopup(marker, markerData, map); //needed since markerData is now a copy
2553                    }
2554                });
2555            });
2556            marker.on("popupclose", function () /* event */{
2557                safeApply(leafletScope, function () {
2558                    markerData.focus = false;
2559                });
2560            });
2561            marker.on("add", function () /* event */{
2562                safeApply(leafletScope, function () {
2563                    if ('label' in markerData) _manageOpenLabel(marker, markerData);
2564                });
2565            });
2566        },
2567
2568        updateMarker: _updateMarker,
2569
2570        addMarkerWatcher: function addMarkerWatcher(marker, name, leafletScope, layers, map, watchOptions) {
2571            var markerWatchPath = Helpers.getObjectArrayPath("markers." + name);
2572
2573            maybeWatch(leafletScope, markerWatchPath, watchOptions, function (markerData, oldMarkerData, clearWatch) {
2574                if (!isDefined(markerData)) {
2575                    _deleteMarker(marker, map, layers);
2576                    clearWatch();
2577                    return;
2578                }
2579                _updateMarker(markerData, oldMarkerData, marker, name, leafletScope, layers, map);
2580            });
2581        },
2582        string: _string,
2583        log: _log,
2584        getModelFromModels: _getModelFromModels,
2585        getLayerModels: _getLayerModels
2586    };
2587});
2588
2589'use strict';
2590
2591angular.module('ui-leaflet').factory('leafletPathsHelpers', function ($rootScope, leafletLogger, leafletHelpers) {
2592    var isDefined = leafletHelpers.isDefined,
2593        isArray = leafletHelpers.isArray,
2594        isNumber = leafletHelpers.isNumber,
2595        isValidPoint = leafletHelpers.isValidPoint,
2596        $log = leafletLogger;
2597
2598    var availableOptions = [
2599    // Path options
2600    'stroke', 'weight', 'color', 'opacity', 'fill', 'fillColor', 'fillOpacity', 'dashArray', 'lineCap', 'lineJoin', 'clickable', 'pointerEvents', 'className',
2601
2602    // Polyline options
2603    'smoothFactor', 'noClip'];
2604    function _convertToLeafletLatLngs(latlngs) {
2605        return latlngs.filter(function (latlng) {
2606            return isValidPoint(latlng);
2607        }).map(function (latlng) {
2608            return _convertToLeafletLatLng(latlng);
2609        });
2610    }
2611
2612    function _convertToLeafletLatLng(latlng) {
2613        if (isArray(latlng)) {
2614            return new L.LatLng(latlng[0], latlng[1]);
2615        } else {
2616            return new L.LatLng(latlng.lat, latlng.lng);
2617        }
2618    }
2619
2620    function _convertToLeafletMultiLatLngs(paths) {
2621        return paths.map(function (latlngs) {
2622            return _convertToLeafletLatLngs(latlngs);
2623        });
2624    }
2625
2626    function _getOptions(path, defaults) {
2627        var options = {};
2628        for (var i = 0; i < availableOptions.length; i++) {
2629            var optionName = availableOptions[i];
2630
2631            if (isDefined(path[optionName])) {
2632                options[optionName] = path[optionName];
2633            } else if (isDefined(defaults.path[optionName])) {
2634                options[optionName] = defaults.path[optionName];
2635            }
2636        }
2637
2638        return options;
2639    }
2640
2641    var _updatePathOptions = function _updatePathOptions(path, data) {
2642        var updatedStyle = {};
2643        for (var i = 0; i < availableOptions.length; i++) {
2644            var optionName = availableOptions[i];
2645            if (isDefined(data[optionName])) {
2646                updatedStyle[optionName] = data[optionName];
2647            }
2648        }
2649        path.setStyle(data);
2650    };
2651
2652    var _isValidPolyline = function _isValidPolyline(latlngs) {
2653        if (!isArray(latlngs)) {
2654            return false;
2655        }
2656        for (var i = 0; i < latlngs.length; i++) {
2657            var point = latlngs[i];
2658            if (!isValidPoint(point)) {
2659                return false;
2660            }
2661        }
2662        return true;
2663    };
2664
2665    var pathTypes = {
2666        polyline: {
2667            isValid: function isValid(pathData) {
2668                var latlngs = pathData.latlngs;
2669                return _isValidPolyline(latlngs);
2670            },
2671            createPath: function createPath(options) {
2672                return new L.Polyline([], options);
2673            },
2674            setPath: function setPath(path, data) {
2675                path.setLatLngs(_convertToLeafletLatLngs(data.latlngs));
2676                _updatePathOptions(path, data);
2677                return;
2678            }
2679        },
2680        multiPolyline: {
2681            isValid: function isValid(pathData) {
2682                var latlngs = pathData.latlngs;
2683                if (!isArray(latlngs)) {
2684                    return false;
2685                }
2686
2687                for (var i in latlngs) {
2688                    var polyline = latlngs[i];
2689                    if (!_isValidPolyline(polyline)) {
2690                        return false;
2691                    }
2692                }
2693
2694                return true;
2695            },
2696            createPath: function createPath(options) {
2697                return new L.multiPolyline([[[0, 0], [1, 1]]], options);
2698            },
2699            setPath: function setPath(path, data) {
2700                path.setLatLngs(_convertToLeafletMultiLatLngs(data.latlngs));
2701                _updatePathOptions(path, data);
2702                return;
2703            }
2704        },
2705        polygon: {
2706            isValid: function isValid(pathData) {
2707                var latlngs = pathData.latlngs;
2708                return _isValidPolyline(latlngs);
2709            },
2710            createPath: function createPath(options) {
2711                return new L.Polygon([], options);
2712            },
2713            setPath: function setPath(path, data) {
2714                path.setLatLngs(_convertToLeafletLatLngs(data.latlngs));
2715                _updatePathOptions(path, data);
2716                return;
2717            }
2718        },
2719        multiPolygon: {
2720            isValid: function isValid(pathData) {
2721                var latlngs = pathData.latlngs;
2722
2723                if (!isArray(latlngs)) {
2724                    return false;
2725                }
2726
2727                for (var i in latlngs) {
2728                    var polyline = latlngs[i];
2729                    if (!_isValidPolyline(polyline)) {
2730                        return false;
2731                    }
2732                }
2733
2734                return true;
2735            },
2736            createPath: function createPath(options) {
2737                return new L.MultiPolygon([[[0, 0], [1, 1], [0, 1]]], options);
2738            },
2739            setPath: function setPath(path, data) {
2740                path.setLatLngs(_convertToLeafletMultiLatLngs(data.latlngs));
2741                _updatePathOptions(path, data);
2742                return;
2743            }
2744        },
2745        rectangle: {
2746            isValid: function isValid(pathData) {
2747                var latlngs = pathData.latlngs;
2748
2749                if (!isArray(latlngs) || latlngs.length !== 2) {
2750                    return false;
2751                }
2752
2753                for (var i in latlngs) {
2754                    var point = latlngs[i];
2755                    if (!isValidPoint(point)) {
2756                        return false;
2757                    }
2758                }
2759
2760                return true;
2761            },
2762            createPath: function createPath(options) {
2763                return new L.Rectangle([[0, 0], [1, 1]], options);
2764            },
2765            setPath: function setPath(path, data) {
2766                path.setBounds(new L.LatLngBounds(_convertToLeafletLatLngs(data.latlngs)));
2767                _updatePathOptions(path, data);
2768            }
2769        },
2770        circle: {
2771            isValid: function isValid(pathData) {
2772                var point = pathData.latlngs;
2773                return isValidPoint(point) && isNumber(pathData.radius);
2774            },
2775            createPath: function createPath(options) {
2776                return new L.Circle([0, 0], 1, options);
2777            },
2778            setPath: function setPath(path, data) {
2779                path.setLatLng(_convertToLeafletLatLng(data.latlngs));
2780                if (isDefined(data.radius)) {
2781                    path.setRadius(data.radius);
2782                }
2783                _updatePathOptions(path, data);
2784            }
2785        },
2786        circleMarker: {
2787            isValid: function isValid(pathData) {
2788                var point = pathData.latlngs;
2789                return isValidPoint(point) && isNumber(pathData.radius);
2790            },
2791            createPath: function createPath(options) {
2792                return new L.CircleMarker([0, 0], options);
2793            },
2794            setPath: function setPath(path, data) {
2795                path.setLatLng(_convertToLeafletLatLng(data.latlngs));
2796                if (isDefined(data.radius)) {
2797                    path.setRadius(data.radius);
2798                }
2799                _updatePathOptions(path, data);
2800            }
2801        }
2802    };
2803
2804    var _getPathData = function _getPathData(path) {
2805        var pathData = {};
2806        if (path.latlngs) {
2807            pathData.latlngs = path.latlngs;
2808        }
2809
2810        if (path.radius) {
2811            pathData.radius = path.radius;
2812        }
2813
2814        return pathData;
2815    };
2816
2817    return {
2818        setPathOptions: function setPathOptions(leafletPath, pathType, data) {
2819            if (!isDefined(pathType)) {
2820                pathType = "polyline";
2821            }
2822            pathTypes[pathType].setPath(leafletPath, data);
2823        },
2824        createPath: function createPath(name, path, defaults) {
2825            if (!isDefined(path.type)) {
2826                path.type = "polyline";
2827            }
2828            var options = _getOptions(path, defaults);
2829            var pathData = _getPathData(path);
2830
2831            if (!pathTypes[path.type].isValid(pathData)) {
2832                $log.error("[AngularJS - Leaflet] Invalid data passed to the " + path.type + " path");
2833                return;
2834            }
2835
2836            return pathTypes[path.type].createPath(options);
2837        }
2838    };
2839});
2840
2841'use strict';
2842
2843angular.module('ui-leaflet').service('leafletWatchHelpers', function () {
2844
2845    var _maybe = function _maybe(scope, watchFunctionName, thingToWatchStr, watchOptions, initCb) {
2846        var unWatch = scope[watchFunctionName](thingToWatchStr, function (newValue, oldValue) {
2847            //make the unWatch function available to the callback as well.
2848            initCb(newValue, oldValue, unWatch);
2849            if (watchOptions.type === null) unWatch();
2850        }, watchOptions.type === 'watchDeep');
2851
2852        return unWatch;
2853    };
2854
2855    /*
2856    @name: maybeWatch
2857    @description: Utility to watch something once or forever.
2858    @returns unWatch function
2859    @param watchOptions - This object is used to determine the type of
2860    watch used.
2861    */
2862    var _maybeWatch = function _maybeWatch(scope, thingToWatchStr, watchOptions, initCb) {
2863        var watchMethod;
2864
2865        if (watchOptions.type === 'watchCollection') {
2866            watchMethod = '$watchCollection';
2867        } else {
2868            watchMethod = '$watch';
2869        }
2870
2871        return _maybe(scope, watchMethod, thingToWatchStr, watchOptions, initCb);
2872    };
2873
2874    return {
2875        maybeWatch: _maybeWatch
2876    };
2877});
2878
2879'use strict';
2880
2881angular.module('ui-leaflet').service('leafletLogger', function (nemSimpleLogger) {
2882  return nemSimpleLogger.spawn();
2883});
2884
2885'use strict';
2886
2887angular.module('ui-leaflet').factory('nominatimService', function ($q, $http, leafletHelpers, leafletMapDefaults) {
2888    var isDefined = leafletHelpers.isDefined;
2889
2890    return {
2891        query: function query(address, mapId) {
2892            var defaults = leafletMapDefaults.getDefaults(mapId);
2893            var url = defaults.nominatim.server;
2894            var df = $q.defer();
2895
2896            $http.get(url, { params: { format: 'json', limit: 1, q: address } }).success(function (data) {
2897                if (data.length > 0 && isDefined(data[0].boundingbox)) {
2898                    df.resolve(data[0]);
2899                } else {
2900                    df.reject('[Nominatim] Invalid address');
2901                }
2902            });
2903
2904            return df.promise;
2905        }
2906    };
2907});
2908
2909'use strict';
2910
2911angular.module('ui-leaflet').directive('bounds', function (leafletLogger, $timeout, $http, leafletHelpers, nominatimService, leafletBoundsHelpers) {
2912    var $log = leafletLogger;
2913    return {
2914        restrict: "A",
2915        scope: false,
2916        replace: false,
2917        require: ['leaflet'],
2918
2919        link: function link(scope, element, attrs, controller) {
2920            var isDefined = leafletHelpers.isDefined;
2921            var createLeafletBounds = leafletBoundsHelpers.createLeafletBounds;
2922            var leafletScope = controller[0].getLeafletScope();
2923            var mapController = controller[0];
2924            var errorHeader = leafletHelpers.errorHeader + ' [Bounds] ';
2925
2926            var emptyBounds = function emptyBounds(bounds) {
2927                return bounds._southWest.lat === 0 && bounds._southWest.lng === 0 && bounds._northEast.lat === 0 && bounds._northEast.lng === 0;
2928            };
2929
2930            mapController.getMap().then(function (map) {
2931                leafletScope.$on('boundsChanged', function (event) {
2932                    var scope = event.currentScope;
2933                    var bounds = map.getBounds();
2934
2935                    if (emptyBounds(bounds) || scope.settingBoundsFromScope) {
2936                        return;
2937                    }
2938                    scope.settingBoundsFromLeaflet = true;
2939                    var newScopeBounds = {
2940                        northEast: {
2941                            lat: bounds._northEast.lat,
2942                            lng: bounds._northEast.lng
2943                        },
2944                        southWest: {
2945                            lat: bounds._southWest.lat,
2946                            lng: bounds._southWest.lng
2947                        },
2948                        options: bounds.options
2949                    };
2950                    if (!angular.equals(scope.bounds, newScopeBounds)) {
2951                        scope.bounds = newScopeBounds;
2952                    }
2953                    $timeout(function () {
2954                        scope.settingBoundsFromLeaflet = false;
2955                    });
2956                });
2957
2958                var lastNominatimQuery;
2959                leafletScope.$watch('bounds', function (bounds) {
2960                    if (scope.settingBoundsFromLeaflet) return;
2961                    if (isDefined(bounds.address) && bounds.address !== lastNominatimQuery) {
2962                        scope.settingBoundsFromScope = true;
2963                        nominatimService.query(bounds.address, attrs.id).then(function (data) {
2964                            var b = data.boundingbox;
2965                            var newBounds = [[b[0], b[2]], [b[1], b[3]]];
2966                            map.fitBounds(newBounds);
2967                        }, function (errMsg) {
2968                            $log.error(errorHeader + ' ' + errMsg + '.');
2969                        });
2970                        lastNominatimQuery = bounds.address;
2971                        $timeout(function () {
2972                            scope.settingBoundsFromScope = false;
2973                        });
2974                        return;
2975                    }
2976
2977                    var leafletBounds = createLeafletBounds(bounds);
2978                    if (leafletBounds && !map.getBounds().equals(leafletBounds)) {
2979                        scope.settingBoundsFromScope = true;
2980                        map.fitBounds(leafletBounds, bounds.options);
2981                        $timeout(function () {
2982                            scope.settingBoundsFromScope = false;
2983                        });
2984                    }
2985                }, true);
2986            });
2987        }
2988    };
2989});
2990
2991'use strict';
2992
2993var centerDirectiveTypes = ['center', 'lfCenter'],
2994    centerDirectives = {};
2995
2996centerDirectiveTypes.forEach(function (directiveName) {
2997    centerDirectives[directiveName] = ['leafletLogger', '$q', '$location', '$timeout', 'leafletMapDefaults', 'leafletHelpers', 'leafletBoundsHelpers', 'leafletMapEvents', function (leafletLogger, $q, $location, $timeout, leafletMapDefaults, leafletHelpers, leafletBoundsHelpers, leafletMapEvents) {
2998
2999        var isDefined = leafletHelpers.isDefined,
3000            isNumber = leafletHelpers.isNumber,
3001            isSameCenterOnMap = leafletHelpers.isSameCenterOnMap,
3002            safeApply = leafletHelpers.safeApply,
3003            isValidCenter = leafletHelpers.isValidCenter,
3004            isValidBounds = leafletBoundsHelpers.isValidBounds,
3005            isUndefinedOrEmpty = leafletHelpers.isUndefinedOrEmpty,
3006            errorHeader = leafletHelpers.errorHeader,
3007            $log = leafletLogger;
3008
3009        var shouldInitializeMapWithBounds = function shouldInitializeMapWithBounds(bounds, center) {
3010            return isDefined(bounds) && isValidBounds(bounds) && isUndefinedOrEmpty(center);
3011        };
3012
3013        var _leafletCenter;
3014        return {
3015            restrict: "A",
3016            scope: false,
3017            replace: false,
3018            require: 'leaflet',
3019            controller: function controller() {
3020                _leafletCenter = $q.defer();
3021                this.getCenter = function () {
3022                    return _leafletCenter.promise;
3023                };
3024            },
3025            link: function link(scope, element, attrs, controller) {
3026                var leafletScope = controller.getLeafletScope(),
3027                    centerModel = leafletScope[directiveName];
3028
3029                controller.getMap().then(function (map) {
3030                    var defaults = leafletMapDefaults.getDefaults(attrs.id);
3031
3032                    if (attrs[directiveName].search("-") !== -1) {
3033                        $log.error(errorHeader + ' The "center" variable can\'t use a "-" on its key name: "' + attrs[directiveName] + '".');
3034                        map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
3035                        return;
3036                    } else if (shouldInitializeMapWithBounds(leafletScope.bounds, centerModel)) {
3037                        map.fitBounds(leafletBoundsHelpers.createLeafletBounds(leafletScope.bounds), leafletScope.bounds.options);
3038                        centerModel = map.getCenter();
3039                        safeApply(leafletScope, function (scope) {
3040                            angular.extend(scope[directiveName], {
3041                                lat: map.getCenter().lat,
3042                                lng: map.getCenter().lng,
3043                                zoom: map.getZoom(),
3044                                autoDiscover: false
3045                            });
3046                        });
3047                        safeApply(leafletScope, function (scope) {
3048                            var mapBounds = map.getBounds();
3049                            scope.bounds = {
3050                                northEast: {
3051                                    lat: mapBounds._northEast.lat,
3052                                    lng: mapBounds._northEast.lng
3053                                },
3054                                southWest: {
3055                                    lat: mapBounds._southWest.lat,
3056                                    lng: mapBounds._southWest.lng
3057                                }
3058                            };
3059                        });
3060                    } else if (!isDefined(centerModel)) {
3061                        $log.error(errorHeader + ' The "center" property is not defined in the main scope');
3062                        map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
3063                        return;
3064                    } else if (!(isDefined(centerModel.lat) && isDefined(centerModel.lng)) && !isDefined(centerModel.autoDiscover)) {
3065                        angular.copy(defaults.center, centerModel);
3066                    }
3067
3068                    var urlCenterHash, mapReady;
3069                    if (attrs.urlHashCenter === "yes") {
3070                        var extractCenterFromUrl = function extractCenterFromUrl() {
3071                            var search = $location.search();
3072                            var centerParam;
3073                            var centerKey = attrs.urlHashParam ? attrs.urlHashParam : 'c';
3074                            if (isDefined(search[centerKey])) {
3075                                var cParam = search[centerKey].split(":");
3076                                if (cParam.length === 3) {
3077                                    centerParam = {
3078                                        lat: parseFloat(cParam[0]),
3079                                        lng: parseFloat(cParam[1]),
3080                                        zoom: parseInt(cParam[2], 10)
3081                                    };
3082                                }
3083                            }
3084                            return centerParam;
3085                        };
3086                        urlCenterHash = extractCenterFromUrl();
3087
3088                        leafletScope.$on('$locationChangeSuccess', function (event) {
3089                            var scope = event.currentScope;
3090                            //$log.debug("updated location...");
3091                            var urlCenter = extractCenterFromUrl();
3092                            if (isDefined(urlCenter) && !isSameCenterOnMap(urlCenter, map)) {
3093                                //$log.debug("updating center model...", urlCenter);
3094                                angular.extend(scope[directiveName], {
3095                                    lat: urlCenter.lat,
3096                                    lng: urlCenter.lng,
3097                                    zoom: urlCenter.zoom
3098                                });
3099                            }
3100                        });
3101                    }
3102
3103                    leafletScope.$watch(directiveName, function (center) {
3104                        if (leafletScope.settingCenterFromLeaflet) return;
3105                        //$log.debug("updated center model...");
3106                        // The center from the URL has priority
3107                        if (isDefined(urlCenterHash)) {
3108                            angular.copy(urlCenterHash, center);
3109                            urlCenterHash = undefined;
3110                        }
3111
3112                        if (!isValidCenter(center) && center.autoDiscover !== true) {
3113                            $log.warn(errorHeader + " invalid 'center'");
3114                            //map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
3115                            return;
3116                        }
3117
3118                        if (center.autoDiscover === true) {
3119                            if (!isNumber(center.zoom)) {
3120                                map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
3121                            }
3122                            if (isNumber(center.zoom) && center.zoom > defaults.center.zoom) {
3123                                map.locate({
3124                                    setView: true,
3125                                    maxZoom: center.zoom
3126                                });
3127                            } else if (isDefined(defaults.maxZoom)) {
3128                                map.locate({
3129                                    setView: true,
3130                                    maxZoom: defaults.maxZoom
3131                                });
3132                            } else {
3133                                map.locate({
3134                                    setView: true
3135                                });
3136                            }
3137                            return;
3138                        }
3139
3140                        if (mapReady && isSameCenterOnMap(center, map)) {
3141                            //$log.debug("no need to update map again.");
3142                            return;
3143                        }
3144
3145                        //$log.debug("updating map center...", center);
3146                        leafletScope.settingCenterFromScope = true;
3147                        map.setView([center.lat, center.lng], center.zoom);
3148                        leafletMapEvents.notifyCenterChangedToBounds(leafletScope, map);
3149                        $timeout(function () {
3150                            leafletScope.settingCenterFromScope = false;
3151                            //$log.debug("allow center scope updates");
3152                        });
3153                    }, true);
3154
3155                    map.whenReady(function () {
3156                        mapReady = true;
3157                    });
3158
3159                    map.on('moveend', function () /* event */{
3160                        // Resolve the center after the first map position
3161                        _leafletCenter.resolve();
3162                        leafletMapEvents.notifyCenterUrlHashChanged(leafletScope, map, attrs, $location.search());
3163                        //$log.debug("updated center on map...");
3164                        if (isSameCenterOnMap(centerModel, map) || leafletScope.settingCenterFromScope) {
3165                            //$log.debug("same center in model, no need to update again.");
3166                            return;
3167                        }
3168                        leafletScope.settingCenterFromLeaflet = true;
3169                        safeApply(leafletScope, function (scope) {
3170                            if (!leafletScope.settingCenterFromScope) {
3171                                //$log.debug("updating center model...", map.getCenter(), map.getZoom());
3172                                angular.extend(scope[directiveName], {
3173                                    lat: map.getCenter().lat,
3174                                    lng: map.getCenter().lng,
3175                                    zoom: map.getZoom(),
3176                                    autoDiscover: false
3177                                });
3178                            }
3179                            leafletMapEvents.notifyCenterChangedToBounds(leafletScope, map);
3180                            $timeout(function () {
3181                                leafletScope.settingCenterFromLeaflet = false;
3182                            });
3183                        });
3184                    });
3185
3186                    if (centerModel.autoDiscover === true) {
3187                        map.on('locationerror', function () {
3188                            $log.warn(errorHeader + " The Geolocation API is unauthorized on this page.");
3189                            if (isValidCenter(centerModel)) {
3190                                map.setView([centerModel.lat, centerModel.lng], centerModel.zoom);
3191                                leafletMapEvents.notifyCenterChangedToBounds(leafletScope, map);
3192                            } else {
3193                                map.setView([defaults.center.lat, defaults.center.lng], defaults.center.zoom);
3194                                leafletMapEvents.notifyCenterChangedToBounds(leafletScope, map);
3195                            }
3196                        });
3197                    }
3198                });
3199            }
3200        };
3201    }];
3202});
3203
3204centerDirectiveTypes.forEach(function (dirType) {
3205    angular.module('ui-leaflet').directive(dirType, centerDirectives[dirType]);
3206});
3207
3208'use strict';
3209
3210angular.module('ui-leaflet').directive('controls', function (leafletLogger, leafletHelpers, leafletControlHelpers) {
3211    var $log = leafletLogger;
3212    return {
3213        restrict: "A",
3214        scope: false,
3215        replace: false,
3216        require: '?^leaflet',
3217
3218        link: function link(scope, element, attrs, controller) {
3219            if (!controller) {
3220                return;
3221            }
3222
3223            var createControl = leafletControlHelpers.createControl;
3224            var isValidControlType = leafletControlHelpers.isValidControlType;
3225            var leafletScope = controller.getLeafletScope();
3226            var isDefined = leafletHelpers.isDefined;
3227            var isArray = leafletHelpers.isArray;
3228            var leafletControls = {};
3229            var errorHeader = leafletHelpers.errorHeader + ' [Controls] ';
3230
3231            scope.$on('$destroy', function () {
3232                leafletControlHelpers.destroyMapLayersControl(scope.mapId);
3233            });
3234
3235            controller.getMap().then(function (map) {
3236
3237                leafletScope.$watchCollection('controls', function (newControls) {
3238
3239                    // Delete controls from the array
3240                    for (var name in leafletControls) {
3241                        if (!isDefined(newControls[name])) {
3242                            if (map.hasControl(leafletControls[name])) {
3243                                map.removeControl(leafletControls[name]);
3244                            }
3245                            delete leafletControls[name];
3246                        }
3247                    }
3248
3249                    for (var newName in newControls) {
3250                        var control;
3251
3252                        var controlType = isDefined(newControls[newName].type) ? newControls[newName].type : newName;
3253
3254                        if (!isValidControlType(controlType)) {
3255                            $log.error(errorHeader + ' Invalid control type: ' + controlType + '.');
3256                            return;
3257                        }
3258
3259                        if (controlType !== 'custom') {
3260                            control = createControl(controlType, newControls[newName]);
3261                            map.addControl(control);
3262                            leafletControls[newName] = control;
3263                        } else {
3264                            var customControlValue = newControls[newName];
3265                            if (isArray(customControlValue)) {
3266                                for (var i = 0; i < customControlValue.length; i++) {
3267                                    var customControl = customControlValue[i];
3268                                    map.addControl(customControl);
3269                                    leafletControls[newName] = !isDefined(leafletControls[newName]) ? [customControl] : leafletControls[newName].concat([customControl]);
3270                                }
3271                            } else {
3272                                map.addControl(customControlValue);
3273                                leafletControls[newName] = customControlValue;
3274                            }
3275                        }
3276                    }
3277                });
3278            });
3279        }
3280    };
3281});
3282
3283"use strict";
3284
3285angular.module('ui-leaflet').directive("decorations", function (leafletLogger, leafletHelpers) {
3286	var $log = leafletLogger;
3287	return {
3288		restrict: "A",
3289		scope: false,
3290		replace: false,
3291		require: 'leaflet',
3292
3293		link: function link(scope, element, attrs, controller) {
3294			var leafletScope = controller.getLeafletScope(),
3295			    PolylineDecoratorPlugin = leafletHelpers.PolylineDecoratorPlugin,
3296			    isDefined = leafletHelpers.isDefined,
3297			    leafletDecorations = {};
3298
3299			/* Creates an "empty" decoration with a set of coordinates, but no pattern. */
3300			function createDecoration(options) {
3301				if (isDefined(options) && isDefined(options.coordinates)) {
3302					if (!PolylineDecoratorPlugin.isLoaded()) {
3303						$log.error('[AngularJS - Leaflet] The PolylineDecorator Plugin is not loaded.');
3304					}
3305				}
3306
3307				return L.polylineDecorator(options.coordinates);
3308			}
3309
3310			/* Updates the path and the patterns for the provided decoration, and returns the decoration. */
3311			function setDecorationOptions(decoration, options) {
3312				if (isDefined(decoration) && isDefined(options)) {
3313					if (isDefined(options.coordinates) && isDefined(options.patterns)) {
3314						decoration.setPaths(options.coordinates);
3315						decoration.setPatterns(options.patterns);
3316						return decoration;
3317					}
3318				}
3319			}
3320
3321			controller.getMap().then(function (map) {
3322				leafletScope.$watch("decorations", function (newDecorations) {
3323					for (var name in leafletDecorations) {
3324						if (!isDefined(newDecorations[name]) || !angular.equals(newDecorations[name], leafletDecorations)) {
3325							map.removeLayer(leafletDecorations[name]);
3326							delete leafletDecorations[name];
3327						}
3328					}
3329
3330					for (var newName in newDecorations) {
3331						var decorationData = newDecorations[newName],
3332						    newDecoration = createDecoration(decorationData);
3333
3334						if (isDefined(newDecoration)) {
3335							leafletDecorations[newName] = newDecoration;
3336							map.addLayer(newDecoration);
3337							setDecorationOptions(newDecoration, decorationData);
3338						}
3339					}
3340				}, true);
3341			});
3342		}
3343	};
3344});
3345
3346'use strict';
3347
3348angular.module('ui-leaflet').directive('eventBroadcast', function (leafletLogger, $rootScope, leafletHelpers, leafletMapEvents, leafletIterators) {
3349    var $log = leafletLogger;
3350    return {
3351        restrict: "A",
3352        scope: false,
3353        replace: false,
3354        require: 'leaflet',
3355
3356        link: function link(scope, element, attrs, controller) {
3357            var isObject = leafletHelpers.isObject,
3358                isDefined = leafletHelpers.isDefined,
3359                leafletScope = controller.getLeafletScope(),
3360                eventBroadcast = leafletScope.eventBroadcast,
3361                availableMapEvents = leafletMapEvents.getAvailableMapEvents(),
3362                addEvents = leafletMapEvents.addEvents;
3363
3364            controller.getMap().then(function (map) {
3365
3366                var mapEvents = [],
3367                    logic = "broadcast";
3368
3369                // We have a possible valid object
3370                if (!isDefined(eventBroadcast.map)) {
3371                    // We do not have events enable/disable do we do nothing (all enabled by default)
3372                    mapEvents = availableMapEvents;
3373                } else if (!isObject(eventBroadcast.map)) {
3374                    // Not a valid object
3375                    $log.warn("[AngularJS - Leaflet] event-broadcast.map must be an object check your model.");
3376                } else {
3377                    // We have a possible valid map object
3378                    // Event propadation logic
3379                    if (eventBroadcast.map.logic !== "emit" && eventBroadcast.map.logic !== "broadcast") {
3380                        // This is an error
3381                        $log.warn("[AngularJS - Leaflet] Available event propagation logic are: 'emit' or 'broadcast'.");
3382                    } else {
3383                        logic = eventBroadcast.map.logic;
3384                    }
3385
3386                    if (!(isObject(eventBroadcast.map.enable) && eventBroadcast.map.enable.length >= 0)) {
3387                        $log.warn("[AngularJS - Leaflet] event-broadcast.map.enable must be an object check your model.");
3388                    } else {
3389                        // Enable events
3390                        leafletIterators.each(eventBroadcast.map.enable, function (eventName) {
3391                            // Do we have already the event enabled?
3392                            if (mapEvents.indexOf(eventName) === -1 && availableMapEvents.indexOf(eventName) !== -1) {
3393                                mapEvents.push(eventName);
3394                            }
3395                        });
3396                    }
3397                }
3398                // as long as the map is removed in the root leaflet directive we
3399                // do not need ot clean up the events as leaflet does it itself
3400                addEvents(map, attrs.id, mapEvents, "eventName", leafletScope, logic);
3401            });
3402        }
3403    };
3404});
3405
3406'use strict';
3407
3408angular.module('ui-leaflet').directive('geojson', function ($timeout, leafletLogger, leafletData, leafletHelpers, leafletWatchHelpers, leafletDirectiveControlsHelpers, leafletIterators, leafletGeoJsonEvents) {
3409    var _maybeWatch = leafletWatchHelpers.maybeWatch,
3410        _defaultWatchOptions = leafletHelpers.watchOptions,
3411        _extendDirectiveControls = leafletDirectiveControlsHelpers.extend,
3412        hlp = leafletHelpers,
3413        $it = leafletIterators,
3414        watchTrap = { changeFromDirective: false };
3415    // $log = leafletLogger;
3416
3417    return {
3418        restrict: "A",
3419        scope: false,
3420        replace: false,
3421        require: 'leaflet',
3422
3423        link: function link(scope, element, attrs, controller) {
3424            var isDefined = leafletHelpers.isDefined,
3425                leafletScope = controller.getLeafletScope(),
3426                leafletGeoJSON = {},
3427                _hasSetLeafletData = false;
3428
3429            controller.getMap().then(function (map) {
3430                var watchOptions;
3431                if (leafletScope.watchOptions && leafletScope.watchOptions.geojson) {
3432                    watchOptions = leafletScope.watchOptions.geojson;
3433                } else {
3434                    watchOptions = _defaultWatchOptions;
3435                }
3436
3437                var _hookUpEvents = function _hookUpEvents(geojson, maybeName) {
3438                    var onEachFeature;
3439
3440                    if (angular.isFunction(geojson.onEachFeature)) {
3441                        onEachFeature = geojson.onEachFeature;
3442                    } else {
3443                        onEachFeature = function onEachFeature(feature, layer) {
3444                            if (leafletHelpers.LabelPlugin.isLoaded() && isDefined(feature.properties.description)) {
3445                                layer.bindLabel(feature.properties.description);
3446                            }
3447
3448                            leafletGeoJsonEvents.bindEvents(attrs.id, layer, null, feature, leafletScope, maybeName, { resetStyleOnMouseout: geojson.resetStyleOnMouseout,
3449                                mapId: attrs.id });
3450                        };
3451                    }
3452                    return onEachFeature;
3453                };
3454
3455                var isNested = hlp.isDefined(attrs.geojsonNested) && hlp.isTruthy(attrs.geojsonNested);
3456
3457                var _clean = function _clean() {
3458                    if (!leafletGeoJSON) return;
3459                    var _remove = function _remove(lObject) {
3460                        if (isDefined(lObject) && map.hasLayer(lObject)) {
3461                            map.removeLayer(lObject);
3462                        }
3463                    };
3464                    if (isNested) {
3465                        $it.each(leafletGeoJSON, function (lObject) {
3466                            _remove(lObject);
3467                        });
3468                        return;
3469                    }
3470                    _remove(leafletGeoJSON);
3471                };
3472
3473                var _addGeojson = function _addGeojson(geojson, maybeName) {
3474
3475                    if (!(isDefined(geojson) && isDefined(geojson.data))) {
3476                        return;
3477                    }
3478                    var onEachFeature = _hookUpEvents(geojson, maybeName);
3479
3480                    if (!isDefined(geojson.options)) {
3481                        hlp.modelChangeInDirective(watchTrap, "changeFromDirective", function () {
3482                            geojson.options = {
3483                                style: geojson.style,
3484                                filter: geojson.filter,
3485                                onEachFeature: onEachFeature,
3486                                pointToLayer: geojson.pointToLayer
3487                            };
3488                        });
3489                    }
3490
3491                    var lObject = L.geoJson(geojson.data, geojson.options);
3492
3493                    if (maybeName && hlp.isString(maybeName)) {
3494                        leafletGeoJSON[maybeName] = lObject;
3495                    } else {
3496                        leafletGeoJSON = lObject;
3497                    }
3498
3499                    lObject.addTo(map);
3500
3501                    if (!_hasSetLeafletData) {
3502                        //only do this once and play with the same ref forever
3503                        _hasSetLeafletData = true;
3504                        leafletData.setGeoJSON(leafletGeoJSON, attrs.id);
3505                    }
3506                };
3507
3508                var _create = function _create(model) {
3509                    _clean();
3510                    if (isNested) {
3511                        if (!model || !Object.keys(model).length) return;
3512                        $it.each(model, function (m, name) {
3513                            //name could be layerName and or groupName
3514                            //for now it is not tied to a layer
3515                            _addGeojson(m, name);
3516                        });
3517                        return;
3518                    }
3519                    _addGeojson(model);
3520                };
3521
3522                _extendDirectiveControls(attrs.id, 'geojson', _create, _clean);
3523
3524                _maybeWatch(leafletScope, 'geojson', watchOptions, function (geojson) {
3525                    if (watchTrap.changeFromDirective) return;
3526                    _create(geojson);
3527                });
3528            });
3529        }
3530    };
3531});
3532
3533'use strict';
3534
3535angular.module('ui-leaflet').directive('layercontrol', function ($filter, leafletLogger, leafletData, leafletHelpers) {
3536    var $log = leafletLogger;
3537    return {
3538        restrict: "E",
3539        scope: {
3540            icons: '=?',
3541            autoHideOpacity: '=?', // Hide other opacity controls when one is activated.
3542            showGroups: '=?', // Hide other opacity controls when one is activated.
3543            title: '@',
3544            baseTitle: '@',
3545            overlaysTitle: '@'
3546        },
3547        replace: true,
3548        transclude: false,
3549        require: '^leaflet',
3550        controller: function controller($scope, $element, $sce) {
3551            $log.debug('[Angular Directive - Layers] layers', $scope, $element);
3552            var safeApply = leafletHelpers.safeApply,
3553                isDefined = leafletHelpers.isDefined;
3554            angular.extend($scope, {
3555                baselayer: '',
3556                oldGroup: '',
3557                layerProperties: {},
3558                groupProperties: {},
3559                rangeIsSupported: leafletHelpers.rangeIsSupported(),
3560                changeBaseLayer: function changeBaseLayer(key, e) {
3561                    leafletHelpers.safeApply($scope, function (scp) {
3562                        scp.baselayer = key;
3563                        leafletData.getMap().then(function (map) {
3564                            leafletData.getLayers().then(function (leafletLayers) {
3565                                if (map.hasLayer(leafletLayers.baselayers[key])) {
3566                                    return;
3567                                }
3568                                for (var i in scp.layers.baselayers) {
3569                                    scp.layers.baselayers[i].icon = scp.icons.unradio;
3570                                    if (map.hasLayer(leafletLayers.baselayers[i])) {
3571                                        map.removeLayer(leafletLayers.baselayers[i]);
3572                                    }
3573                                }
3574                                map.addLayer(leafletLayers.baselayers[key]);
3575                                scp.layers.baselayers[key].icon = $scope.icons.radio;
3576                            });
3577                        });
3578                    });
3579                    e.preventDefault();
3580                },
3581                moveLayer: function moveLayer(ly, newIndex, e) {
3582                    var delta = Object.keys($scope.layers.baselayers).length;
3583                    if (newIndex >= 1 + delta && newIndex <= $scope.overlaysArray.length + delta) {
3584                        var oldLy;
3585                        for (var key in $scope.layers.overlays) {
3586                            if ($scope.layers.overlays[key].index === newIndex) {
3587                                oldLy = $scope.layers.overlays[key];
3588                                break;
3589                            }
3590                        }
3591                        if (oldLy) {
3592                            safeApply($scope, function () {
3593                                oldLy.index = ly.index;
3594                                ly.index = newIndex;
3595                            });
3596                        }
3597                    }
3598                    e.stopPropagation();
3599                    e.preventDefault();
3600                },
3601                initIndex: function initIndex(layer, idx) {
3602                    var delta = Object.keys($scope.layers.baselayers).length;
3603                    layer.index = isDefined(layer.index) ? layer.index : idx + delta + 1;
3604                },
3605                initGroup: function initGroup(groupName) {
3606                    $scope.groupProperties[groupName] = $scope.groupProperties[groupName] ? $scope.groupProperties[groupName] : {};
3607                },
3608                toggleOpacity: function toggleOpacity(e, layer) {
3609                    if (layer.visible) {
3610                        if ($scope.autoHideOpacity && !$scope.layerProperties[layer.name].opacityControl) {
3611                            for (var k in $scope.layerProperties) {
3612                                $scope.layerProperties[k].opacityControl = false;
3613                            }
3614                        }
3615                        $scope.layerProperties[layer.name].opacityControl = !$scope.layerProperties[layer.name].opacityControl;
3616                    }
3617                    e.stopPropagation();
3618                    e.preventDefault();
3619                },
3620                toggleLegend: function toggleLegend(layer) {
3621                    $scope.layerProperties[layer.name].showLegend = !$scope.layerProperties[layer.name].showLegend;
3622                },
3623                showLegend: function showLegend(layer) {
3624                    return layer.legend && $scope.layerProperties[layer.name].showLegend;
3625                },
3626                unsafeHTML: function unsafeHTML(html) {
3627                    return $sce.trustAsHtml(html);
3628                },
3629                getOpacityIcon: function getOpacityIcon(layer) {
3630                    return layer.visible && $scope.layerProperties[layer.name].opacityControl ? $scope.icons.close : $scope.icons.open;
3631                },
3632                getGroupIcon: function getGroupIcon(group) {
3633                    return group.visible ? $scope.icons.check : $scope.icons.uncheck;
3634                },
3635                changeGroupVisibility: function changeGroupVisibility(groupName) {
3636                    if (!isDefined($scope.groupProperties[groupName])) {
3637                        return;
3638                    }
3639                    var visible = $scope.groupProperties[groupName].visible;
3640                    for (var k in $scope.layers.overlays) {
3641                        var layer = $scope.layers.overlays[k];
3642                        if (layer.group === groupName) {
3643                            layer.visible = visible;
3644                        }
3645                    }
3646                }
3647            });
3648
3649            var div = $element.get(0);
3650            if (!L.Browser.touch) {
3651                L.DomEvent.disableClickPropagation(div);
3652                L.DomEvent.on(div, 'mousewheel', L.DomEvent.stopPropagation);
3653            } else {
3654                L.DomEvent.on(div, 'click', L.DomEvent.stopPropagation);
3655            }
3656        },
3657        template: '<div class="angular-leaflet-control-layers" ng-show="overlaysArray.length">' + '<h4 ng-if="title">{{ title }}</h4>' + '<div class="lf-baselayers">' + '<h5 class="lf-title" ng-if="baseTitle">{{ baseTitle }}</h5>' + '<div class="lf-row" ng-repeat="(key, layer) in baselayersArray">' + '<label class="lf-icon-bl" ng-click="changeBaseLayer(key, $event)">' + '<input class="leaflet-control-layers-selector" type="radio" name="lf-radio" ' + 'ng-show="false" ng-checked="baselayer === key" ng-value="key" /> ' + '<i class="lf-icon lf-icon-radio" ng-class="layer.icon"></i>' + '<div class="lf-text">{{layer.name}}</div>' + '</label>' + '</div>' + '</div>' + '<div class="lf-overlays">' + '<h5 class="lf-title" ng-if="overlaysTitle">{{ overlaysTitle }}</h5>' + '<div class="lf-container">' + '<div class="lf-row" ng-repeat="layer in (o = (overlaysArray | orderBy:\'index\':order))" ng-init="initIndex(layer, $index)">' + '<label class="lf-icon-ol-group" ng-if="showGroups &amp;&amp; layer.group &amp;&amp; layer.group != o[$index-1].group">' + '<input class="lf-control-layers-selector" type="checkbox" ng-show="false" ' + 'ng-change="changeGroupVisibility(layer.group)" ng-model="groupProperties[layer.group].visible"/> ' + '<i class="lf-icon lf-icon-check" ng-class="getGroupIcon(groupProperties[layer.group])"></i>' + '<div class="lf-text">{{ layer.group }}</div>' + '</label>' + '<label class="lf-icon-ol">' + '<input class="lf-control-layers-selector" type="checkbox" ng-show="false" ng-model="layer.visible"/> ' + '<i class="lf-icon lf-icon-check" ng-class="layer.icon"></i>' + '<div class="lf-text">{{layer.name}}</div>' + '</label>' + '<div class="lf-icons">' + '<i class="lf-icon lf-up" ng-class="icons.up" ng-click="moveLayer(layer, layer.index - orderNumber, $event)"></i> ' + '<i class="lf-icon lf-down" ng-class="icons.down" ng-click="moveLayer(layer, layer.index + orderNumber, $event)"></i> ' + '<i class="lf-icon lf-toggle-legend" ng-class="icons.toggleLegend" ng-if="layer.legend" ng-click="toggleLegend(layer)"></i> ' + '<i class="lf-icon lf-open" ng-class="getOpacityIcon(layer)" ng-click="toggleOpacity($event, layer)"></i>' + '</div>' + '<div class="lf-legend" ng-if="showLegend(layer)" ng-bind-html="unsafeHTML(layer.legend)"></div>' + '<div class="lf-opacity clearfix" ng-if="layer.visible &amp;&amp; layerProperties[layer.name].opacityControl">' + '<label ng-if="rangeIsSupported" class="pull-left" style="width: 50%">0</label>' + '<label ng-if="rangeIsSupported" class="pull-left text-right" style="width: 50%">100</label>' + '<input ng-if="rangeIsSupported" class="clearfix" type="range" min="0" max="1" step="0.05" ' + 'class="lf-opacity-control" ng-model="layerProperties[layer.name].layerOptions.opacity"/>' + '<h6 ng-if="!rangeIsSupported">Range is not supported in this browser</h6>' + '</div>' + '</div>' + '</div>' + '</div>' + '</div>',
3658        link: function link(scope, element, attrs, controller) {
3659            var isDefined = leafletHelpers.isDefined,
3660                leafletScope = controller.getLeafletScope(),
3661                layers = leafletScope.layers;
3662
3663            scope.$watch('icons', function () {
3664                var defaultIcons = {
3665                    uncheck: 'fa fa-square-o',
3666                    check: 'fa fa-check-square-o',
3667                    radio: 'fa fa-dot-circle-o',
3668                    unradio: 'fa fa-circle-o',
3669                    up: 'fa fa-angle-up',
3670                    down: 'fa fa-angle-down',
3671                    open: 'fa fa-angle-double-down',
3672                    close: 'fa fa-angle-double-up',
3673                    toggleLegend: 'fa fa-pencil-square-o'
3674                };
3675                if (isDefined(scope.icons)) {
3676                    angular.extend(defaultIcons, scope.icons);
3677                    angular.extend(scope.icons, defaultIcons);
3678                } else {
3679                    scope.icons = defaultIcons;
3680                }
3681            });
3682
3683            // Setting layer stack order.
3684            attrs.order = isDefined(attrs.order) && (attrs.order === 'normal' || attrs.order === 'reverse') ? attrs.order : 'normal';
3685            scope.order = attrs.order === 'normal';
3686            scope.orderNumber = attrs.order === 'normal' ? -1 : 1;
3687
3688            scope.layers = layers;
3689            controller.getMap().then(function (map) {
3690                leafletScope.$watch('layers.baselayers', function (newBaseLayers) {
3691                    var baselayersArray = {};
3692                    leafletData.getLayers().then(function (leafletLayers) {
3693                        var key;
3694                        for (key in newBaseLayers) {
3695                            var layer = newBaseLayers[key];
3696                            layer.icon = scope.icons[map.hasLayer(leafletLayers.baselayers[key]) ? 'radio' : 'unradio'];
3697                            baselayersArray[key] = layer;
3698                        }
3699                        scope.baselayersArray = baselayersArray;
3700                    });
3701                });
3702
3703                leafletScope.$watch('layers.overlays', function (newOverlayLayers) {
3704                    var overlaysArray = [];
3705                    var groupVisibleCount = {};
3706                    leafletData.getLayers().then(function () {
3707                        var key;
3708                        for (key in newOverlayLayers) {
3709                            var layer = newOverlayLayers[key];
3710                            layer.icon = scope.icons[layer.visible ? 'check' : 'uncheck'];
3711                            overlaysArray.push(layer);
3712
3713                            if (!isDefined(scope.layerProperties[layer.name])) {
3714                                if (isDefined(layer.layerOptions.opacity)) {
3715                                    layer.layerOptions.opacity = 1;
3716                                }
3717                                scope.layerProperties[layer.name] = {
3718                                    opacityControl: false,
3719                                    showLegend: true,
3720                                    layerOptions: layer.layerOptions
3721                                };
3722                            }
3723                            if (isDefined(layer.group)) {
3724                                if (!isDefined(scope.groupProperties[layer.group])) {
3725                                    scope.groupProperties[layer.group] = {
3726                                        visible: false
3727                                    };
3728                                }
3729                                groupVisibleCount[layer.group] = isDefined(groupVisibleCount[layer.group]) ? groupVisibleCount[layer.group] : {
3730                                    count: 0,
3731                                    visibles: 0
3732                                };
3733                                groupVisibleCount[layer.group].count++;
3734                                if (layer.visible) {
3735                                    groupVisibleCount[layer.group].visibles++;
3736                                }
3737                            }
3738                            /*
3739                            if(isDefined(layer.index) && leafletLayers.overlays[key].setZIndex) {
3740                                leafletLayers.overlays[key].setZIndex(newOverlayLayers[key].index);
3741                            }
3742                            */
3743                        }
3744
3745                        for (key in groupVisibleCount) {
3746                            scope.groupProperties[key].visible = groupVisibleCount[key].visibles === groupVisibleCount[key].count;
3747                        }
3748                        scope.overlaysArray = overlaysArray;
3749                    });
3750                }, true);
3751            });
3752        }
3753    };
3754});
3755
3756'use strict';
3757
3758angular.module('ui-leaflet').directive('layers', function (leafletLogger, $q, leafletData, leafletHelpers, leafletLayerHelpers, leafletControlHelpers) {
3759    // var $log = leafletLogger;
3760    return {
3761        restrict: "A",
3762        scope: false,
3763        replace: false,
3764        require: 'leaflet',
3765        controller: function controller($scope) {
3766            $scope._leafletLayers = $q.defer();
3767            this.getLayers = function () {
3768                return $scope._leafletLayers.promise;
3769            };
3770        },
3771        link: function link(scope, element, attrs, controller) {
3772            var isDefined = leafletHelpers.isDefined,
3773                leafletLayers = {},
3774                leafletScope = controller.getLeafletScope(),
3775                layers = leafletScope.layers,
3776                createLayer = leafletLayerHelpers.createLayer,
3777                safeAddLayer = leafletLayerHelpers.safeAddLayer,
3778                safeRemoveLayer = leafletLayerHelpers.safeRemoveLayer,
3779                changeOpacityListener = leafletLayerHelpers.changeOpacityListener,
3780                updateLayersControl = leafletControlHelpers.updateLayersControl,
3781                isLayersControlVisible = false;
3782
3783            scope.$on('$destroy', function () {
3784                leafletControlHelpers.destroyMapLayersControl(scope.mapId);
3785            });
3786
3787            controller.getMap().then(function (map) {
3788
3789                // We have baselayers to add to the map
3790                scope._leafletLayers.resolve(leafletLayers);
3791                leafletData.setLayers(leafletLayers, attrs.id);
3792
3793                leafletLayers.baselayers = {};
3794                leafletLayers.overlays = {};
3795
3796                var mapId = attrs.id;
3797
3798                // Setup all baselayers definitions
3799                var oneVisibleLayer = false;
3800                for (var layerName in layers.baselayers) {
3801                    var newBaseLayer = createLayer(layers.baselayers[layerName]);
3802                    if (!isDefined(newBaseLayer)) {
3803                        delete layers.baselayers[layerName];
3804                        continue;
3805                    }
3806                    leafletLayers.baselayers[layerName] = newBaseLayer;
3807                    // Only add the visible layer to the map, layer control manages the addition to the map
3808                    // of layers in its control
3809                    if (layers.baselayers[layerName].top === true) {
3810                        safeAddLayer(map, leafletLayers.baselayers[layerName]);
3811                        oneVisibleLayer = true;
3812                    }
3813                }
3814
3815                // If there is no visible layer add first to the map
3816                if (!oneVisibleLayer && Object.keys(leafletLayers.baselayers).length > 0) {
3817                    safeAddLayer(map, leafletLayers.baselayers[Object.keys(layers.baselayers)[0]]);
3818                }
3819
3820                // Setup the Overlays
3821                for (layerName in layers.overlays) {
3822                    if (layers.overlays[layerName].type === 'cartodb') {}
3823                    var newOverlayLayer = createLayer(layers.overlays[layerName]);
3824                    if (!isDefined(newOverlayLayer)) {
3825                        delete layers.overlays[layerName];
3826                        continue;
3827                    }
3828                    leafletLayers.overlays[layerName] = newOverlayLayer;
3829                    // Only add the visible overlays to the map
3830                    if (layers.overlays[layerName].visible === true) {
3831                        safeAddLayer(map, leafletLayers.overlays[layerName]);
3832                    }
3833                }
3834
3835                // Watch for the base layers
3836                leafletScope.$watch('layers.baselayers', function (newBaseLayers, oldBaseLayers) {
3837                    if (angular.equals(newBaseLayers, oldBaseLayers)) {
3838                        isLayersControlVisible = updateLayersControl(map, mapId, isLayersControlVisible, newBaseLayers, layers.overlays, leafletLayers);
3839                        return true;
3840                    }
3841                    // Delete layers from the array
3842                    for (var name in leafletLayers.baselayers) {
3843                        if (!isDefined(newBaseLayers[name]) || newBaseLayers[name].doRefresh) {
3844                            // Remove from the map if it's on it
3845                            if (map.hasLayer(leafletLayers.baselayers[name])) {
3846                                map.removeLayer(leafletLayers.baselayers[name]);
3847                            }
3848                            delete leafletLayers.baselayers[name];
3849
3850                            if (newBaseLayers[name] && newBaseLayers[name].doRefresh) {
3851                                newBaseLayers[name].doRefresh = false;
3852                            }
3853                        }
3854                    }
3855                    // add new layers
3856                    for (var newName in newBaseLayers) {
3857                        if (!isDefined(leafletLayers.baselayers[newName])) {
3858                            var testBaseLayer = createLayer(newBaseLayers[newName]);
3859                            if (isDefined(testBaseLayer)) {
3860                                leafletLayers.baselayers[newName] = testBaseLayer;
3861                                // Only add the visible layer to the map
3862                                if (newBaseLayers[newName].top === true) {
3863                                    safeAddLayer(map, leafletLayers.baselayers[newName]);
3864                                }
3865                            }
3866                        } else {
3867                            if (newBaseLayers[newName].top === true && !map.hasLayer(leafletLayers.baselayers[newName])) {
3868                                safeAddLayer(map, leafletLayers.baselayers[newName]);
3869                            } else if (newBaseLayers[newName].top === false && map.hasLayer(leafletLayers.baselayers[newName])) {
3870                                map.removeLayer(leafletLayers.baselayers[newName]);
3871                            }
3872                        }
3873                    }
3874
3875                    //we have layers, so we need to make, at least, one active
3876                    var found = false;
3877                    // search for an active layer
3878                    for (var key in leafletLayers.baselayers) {
3879                        if (map.hasLayer(leafletLayers.baselayers[key])) {
3880                            found = true;
3881                            break;
3882                        }
3883                    }
3884                    // If there is no active layer make one active
3885                    if (!found && Object.keys(leafletLayers.baselayers).length > 0) {
3886                        safeAddLayer(map, leafletLayers.baselayers[Object.keys(leafletLayers.baselayers)[0]]);
3887                    }
3888
3889                    // Only show the layers switch selector control if we have more than one baselayer + overlay
3890                    isLayersControlVisible = updateLayersControl(map, mapId, isLayersControlVisible, newBaseLayers, layers.overlays, leafletLayers);
3891                }, true);
3892
3893                // Watch for the overlay layers
3894                leafletScope.$watch('layers.overlays', function (newOverlayLayers, oldOverlayLayers) {
3895                    if (angular.equals(newOverlayLayers, oldOverlayLayers)) {
3896                        isLayersControlVisible = updateLayersControl(map, mapId, isLayersControlVisible, layers.baselayers, newOverlayLayers, leafletLayers);
3897                        return true;
3898                    }
3899
3900                    // Delete layers from the array
3901                    for (var name in leafletLayers.overlays) {
3902                        if (!isDefined(newOverlayLayers[name]) || newOverlayLayers[name].doRefresh) {
3903                            // Remove from the map if it's on it
3904                            if (map.hasLayer(leafletLayers.overlays[name])) {
3905                                // Safe remove when ArcGIS layers is loading.
3906                                var options = isDefined(newOverlayLayers[name]) ? newOverlayLayers[name].layerOptions : null;
3907                                safeRemoveLayer(map, leafletLayers.overlays[name], options);
3908                            }
3909                            // TODO: Depending on the layer type we will have to delete what's included on it
3910                            delete leafletLayers.overlays[name];
3911
3912                            if (newOverlayLayers[name] && newOverlayLayers[name].doRefresh) {
3913                                newOverlayLayers[name].doRefresh = false;
3914                            }
3915                        }
3916                    }
3917
3918                    // add new overlays
3919                    for (var newName in newOverlayLayers) {
3920                        if (!isDefined(leafletLayers.overlays[newName])) {
3921                            var testOverlayLayer = createLayer(newOverlayLayers[newName]);
3922                            if (!isDefined(testOverlayLayer)) {
3923                                // If the layer creation fails, continue to the next overlay
3924                                continue;
3925                            }
3926                            leafletLayers.overlays[newName] = testOverlayLayer;
3927                            if (newOverlayLayers[newName].visible === true) {
3928                                safeAddLayer(map, leafletLayers.overlays[newName]);
3929                            }
3930
3931                            if (isDefined(newOverlayLayers[newName].index) && leafletLayers.overlays[newName].setZIndex) {
3932                                leafletLayers.overlays[newName].setZIndex(newOverlayLayers[newName].index);
3933                            }
3934                        } else {
3935                            // check for the .visible property to hide/show overLayers
3936                            if (newOverlayLayers[newName].visible && !map.hasLayer(leafletLayers.overlays[newName])) {
3937                                safeAddLayer(map, leafletLayers.overlays[newName]);
3938                            } else if (newOverlayLayers[newName].visible === false && map.hasLayer(leafletLayers.overlays[newName])) {
3939                                // Safe remove when ArcGIS layers is loading.
3940                                safeRemoveLayer(map, leafletLayers.overlays[newName], newOverlayLayers[newName].layerOptions);
3941                            }
3942
3943                            // check for the .layerOptions.opacity property has changed.
3944                            var ly = leafletLayers.overlays[newName];
3945                            if (map.hasLayer(leafletLayers.overlays[newName])) {
3946                                if (newOverlayLayers[newName].layerOptions.opacity !== oldOverlayLayers[newName].layerOptions.opacity) {
3947
3948                                    if (isDefined(ly.setOpacity)) {
3949                                        ly.setOpacity(newOverlayLayers[newName].layerOptions.opacity);
3950                                    }
3951                                    if (isDefined(ly.getLayers) && isDefined(ly.eachLayer)) {
3952                                        ly.eachLayer(changeOpacityListener(newOverlayLayers[newName].layerOptions.opacity));
3953                                    }
3954                                }
3955
3956                                if (isDefined(newOverlayLayers[newName].index) && ly.setZIndex && newOverlayLayers[newName].index !== oldOverlayLayers[newName].index) {
3957                                    ly.setZIndex(newOverlayLayers[newName].index);
3958                                }
3959                            }
3960                        }
3961
3962                        //refresh heatmap data if present
3963                        if (newOverlayLayers[newName].visible && map._loaded && newOverlayLayers[newName].data && newOverlayLayers[newName].type === "heatmap") {
3964                            leafletLayers.overlays[newName].setData(newOverlayLayers[newName].data);
3965                            leafletLayers.overlays[newName].update();
3966                        }
3967                    }
3968
3969                    // Only add the layers switch selector control if we have more than one baselayer + overlay
3970                    isLayersControlVisible = updateLayersControl(map, mapId, isLayersControlVisible, layers.baselayers, newOverlayLayers, leafletLayers);
3971                }, true);
3972            });
3973        }
3974    };
3975});
3976
3977'use strict';
3978
3979angular.module("ui-leaflet").directive('legend', function (leafletLogger, $http, $timeout, leafletHelpers, leafletLegendHelpers) {
3980    var $log = leafletLogger,
3981        errorHeader = leafletHelpers.errorHeader + ' [Legend] ';
3982    return {
3983        restrict: "A",
3984        scope: false,
3985        replace: false,
3986        require: 'leaflet',
3987        transclude: false,
3988
3989        link: function link(scope, element, attrs, controller) {
3990
3991            var isArray = leafletHelpers.isArray,
3992                isString = leafletHelpers.isString,
3993                isDefined = leafletHelpers.isDefined,
3994                isFunction = leafletHelpers.isFunction,
3995                leafletScope = controller.getLeafletScope(),
3996                legend = leafletScope.legend;
3997
3998            var legendClass;
3999            var position;
4000            var leafletLegend;
4001            var type;
4002
4003            leafletScope.$watch('legend', function (newLegend) {
4004
4005                if (isDefined(newLegend)) {
4006                    legendClass = newLegend.legendClass ? newLegend.legendClass : "legend";
4007                    position = newLegend.position || 'bottomright';
4008                    // default to arcgis
4009                    type = newLegend.type || 'arcgis';
4010                }
4011            }, true);
4012
4013            var createLegend = function createLegend(map, legendData, newURL) {
4014                if (legendData && legendData.layers && legendData.layers.length > 0) {
4015                    if (isDefined(leafletLegend)) {
4016                        leafletLegendHelpers.updateLegend(leafletLegend.getContainer(), legendData, type, newURL);
4017                    } else {
4018                        leafletLegend = L.control({
4019                            position: position
4020                        });
4021                        leafletLegend.onAdd = leafletLegendHelpers.getOnAddLegend(legendData, legendClass, type, newURL);
4022                        leafletLegend.addTo(map);
4023                    }
4024
4025                    if (isDefined(legend.loadedData) && isFunction(legend.loadedData)) {
4026                        legend.loadedData();
4027                    }
4028                }
4029            };
4030
4031            controller.getMap().then(function (map) {
4032                leafletScope.$watch('legend', function (newLegend) {
4033                    if (!isDefined(newLegend)) {
4034                        if (isDefined(leafletLegend)) {
4035                            leafletLegend.removeFrom(map);
4036                            leafletLegend = null;
4037                        }
4038
4039                        return;
4040                    }
4041
4042                    if (!isDefined(newLegend.url) && type === 'arcgis' && (!isArray(newLegend.colors) || !isArray(newLegend.labels) || newLegend.colors.length !== newLegend.labels.length)) {
4043                        $log.warn(errorHeader + " legend.colors and legend.labels must be set.");
4044                        return;
4045                    }
4046
4047                    if (isDefined(newLegend.url)) {
4048                        $log.info(errorHeader + " loading legend service.");
4049                        return;
4050                    }
4051
4052                    if (isDefined(leafletLegend)) {
4053                        leafletLegend.removeFrom(map);
4054                        leafletLegend = null;
4055                    }
4056
4057                    leafletLegend = L.control({
4058                        position: position
4059                    });
4060
4061                    if (type === 'arcgis') {
4062                        leafletLegend.onAdd = leafletLegendHelpers.getOnAddArrayLegend(newLegend, legendClass);
4063                    }
4064                    leafletLegend.addTo(map);
4065                });
4066
4067                leafletScope.$watch('legend.url', function (newURL) {
4068                    if (!isDefined(newURL)) {
4069                        return;
4070                    }
4071
4072                    if (!isArray(newURL) && !isString(newURL)) {
4073                        $log.warn(errorHeader + " legend.url must be an array or string.");
4074                        return;
4075                    }
4076
4077                    var urls = isString(newURL) ? [newURL] : newURL;
4078
4079                    var legendData;
4080                    var onResult = function onResult(idx, url) {
4081                        return function (ld) {
4082                            if (isDefined(ld.data.error)) {
4083                                $log.warn(errorHeader + 'Error loadin legend from: ' + url, ld.data.error.message);
4084                            } else {
4085                                if (legendData && legendData.layers && legendData.layers.length > 0) {
4086                                    legendData.layers = legendData.layers.concat(ld.data.layers);
4087                                } else {
4088                                    legendData = ld.data;
4089                                }
4090                            }
4091
4092                            if (idx === urls.length - 1) {
4093                                createLegend(map, legendData, newURL);
4094                            }
4095                        };
4096                    };
4097                    var onError = function onError(err) {
4098                        $log.warn(errorHeader + ' legend.url not loaded.', err);
4099                    };
4100
4101                    for (var i = 0; i < urls.length; i++) {
4102                        leafletLegendHelpers.addLegendURL(attrs.id, {
4103                            url: urls[i],
4104                            method: 'GET'
4105                        }).then(onResult(i)).catch(onError);
4106                    }
4107                });
4108
4109                leafletScope.$watch('legend.legendData', function (legendData) {
4110                    $log.debug('legendData', legendData);
4111                    if (isDefined(leafletScope.legend.url) || !isDefined(legendData)) {
4112                        return;
4113                    }
4114
4115                    createLegend(map, legendData);
4116                }, true);
4117            });
4118        }
4119    };
4120});
4121
4122'use strict';
4123
4124angular.module('ui-leaflet').directive('markers', function (leafletLogger, $rootScope, $q, leafletData, leafletHelpers, leafletMapDefaults, leafletMarkersHelpers, leafletMarkerEvents, leafletIterators, leafletWatchHelpers, leafletDirectiveControlsHelpers) {
4125    //less terse vars to helpers
4126    var isDefined = leafletHelpers.isDefined,
4127        errorHeader = leafletHelpers.errorHeader,
4128        Helpers = leafletHelpers,
4129        isString = leafletHelpers.isString,
4130        addMarkerWatcher = leafletMarkersHelpers.addMarkerWatcher,
4131        updateMarker = leafletMarkersHelpers.updateMarker,
4132        listenMarkerEvents = leafletMarkersHelpers.listenMarkerEvents,
4133        addMarkerToGroup = leafletMarkersHelpers.addMarkerToGroup,
4134        createMarker = leafletMarkersHelpers.createMarker,
4135        deleteMarker = leafletMarkersHelpers.deleteMarker,
4136        getModelFromModels = leafletMarkersHelpers.getModelFromModels,
4137        getLayerModels = leafletMarkersHelpers.getLayerModels,
4138        resetUnusedMarkerGroups = leafletMarkersHelpers.resetUnusedMarkerGroups,
4139        $it = leafletIterators,
4140        _defaultWatchOptions = leafletHelpers.watchOptions,
4141        maybeWatch = leafletWatchHelpers.maybeWatch,
4142        extendDirectiveControls = leafletDirectiveControlsHelpers.extend,
4143        $log = leafletLogger,
4144        watchTrap = { changeFromDirective: false };
4145
4146    var _getLMarker = function _getLMarker(leafletMarkers, name, maybeLayerName) {
4147        if (!Object.keys(leafletMarkers).length) return;
4148        if (maybeLayerName && isString(maybeLayerName)) {
4149            if (!leafletMarkers[maybeLayerName] || !Object.keys(leafletMarkers[maybeLayerName]).length) return;
4150            return leafletMarkers[maybeLayerName][name];
4151        }
4152        return leafletMarkers[name];
4153    };
4154
4155    var _setLMarker = function _setLMarker(lObject, leafletMarkers, name, maybeLayerName) {
4156        if (maybeLayerName && isString(maybeLayerName)) {
4157            if (!isDefined(leafletMarkers[maybeLayerName])) leafletMarkers[maybeLayerName] = {};
4158            leafletMarkers[maybeLayerName][name] = lObject;
4159        } else leafletMarkers[name] = lObject;
4160        return lObject;
4161    };
4162
4163    var _maybeAddMarkerToLayer = function _maybeAddMarkerToLayer(layerName, layers, model, marker, watchType, map) {
4164
4165        if (!isString(layerName)) {
4166            $log.error(errorHeader + ' A layername must be a string');
4167            return false;
4168        }
4169
4170        if (!isDefined(layers)) {
4171            $log.error(errorHeader + ' You must add layers to the directive if the markers are going to use this functionality.');
4172            return false;
4173        }
4174
4175        if (!isDefined(layers.overlays) || !isDefined(layers.overlays[layerName])) {
4176            $log.error(errorHeader + ' A marker can only be added to a layer of type "group"');
4177            return false;
4178        }
4179        var layerGroup = layers.overlays[layerName];
4180        if (!(layerGroup instanceof L.LayerGroup || layerGroup instanceof L.FeatureGroup)) {
4181            $log.error(errorHeader + ' Adding a marker to an overlay needs a overlay of the type "group" or "featureGroup"');
4182            return false;
4183        }
4184
4185        // The marker goes to a correct layer group, so first of all we add it
4186        layerGroup.addLayer(marker);
4187
4188        // The marker is automatically added to the map depending on the visibility
4189        // of the layer, so we only have to open the popup if the marker is in the map
4190        if (watchType === null && map.hasLayer(marker) && model.focus === true) {
4191            marker.openPopup();
4192        }
4193        return true;
4194    };
4195    //TODO: move to leafletMarkersHelpers??? or make a new class/function file (leafletMarkersHelpers is large already)
4196    var _addMarkers = function _addMarkers(mapId, markersToRender, oldModels, map, layers, leafletMarkers, leafletScope, watchOptions, maybeLayerName, skips) {
4197        $it.each(markersToRender, function (model, newName) {
4198            if (skips[newName]) return;
4199
4200            if (newName.search("-") !== -1) {
4201                $log.error('The marker can\'t use a "-" on his key name: "' + newName + '".');
4202                return;
4203            }
4204
4205            var pathToMarker = Helpers.getObjectDotPath(maybeLayerName ? [maybeLayerName, newName] : [newName]);
4206            var maybeLMarker = _getLMarker(leafletMarkers, newName, maybeLayerName);
4207            Helpers.modelChangeInDirective(watchTrap, "changeFromDirective", function () {
4208                if (!isDefined(maybeLMarker)) {
4209
4210                    var marker = createMarker(model);
4211                    var layerName = (model ? model.layer : undefined) || maybeLayerName; //original way takes pref
4212                    if (!isDefined(marker)) {
4213                        $log.error(errorHeader + ' Received invalid data on the marker ' + newName + '.');
4214                        return;
4215                    }
4216                    _setLMarker(marker, leafletMarkers, newName, maybeLayerName);
4217
4218                    // Bind message
4219                    if (isDefined(model.message)) {
4220                        marker.bindPopup(model.message, model.popupOptions);
4221                    }
4222
4223                    // Add the marker to a cluster group if needed
4224                    if (isDefined(model.group)) {
4225                        var groupOptions = isDefined(model.groupOption) ? model.groupOption : null;
4226                        addMarkerToGroup(marker, model.group, groupOptions, map);
4227                    }
4228
4229                    // Show label if defined
4230                    if (Helpers.LabelPlugin.isLoaded() && isDefined(model.label) && isDefined(model.label.message)) {
4231                        marker.bindLabel(model.label.message, model.label.options);
4232                    }
4233
4234                    // Check if the marker should be added to a layer
4235                    if (isDefined(model) && (isDefined(model.layer) || isDefined(maybeLayerName))) {
4236
4237                        var pass = _maybeAddMarkerToLayer(layerName, layers, model, marker, watchOptions.individual.type, map);
4238                        if (!pass) return; //something went wrong move on in the loop
4239                    } else if (!isDefined(model.group)) {
4240                        // We do not have a layer attr, so the marker goes to the map layer
4241                        map.addLayer(marker);
4242                        if (watchOptions.individual.type === null && model.focus === true) {
4243                            marker.openPopup();
4244                        }
4245                    }
4246
4247                    if (watchOptions.individual.type !== null) {
4248                        addMarkerWatcher(marker, pathToMarker, leafletScope, layers, map, watchOptions.individual);
4249                    }
4250
4251                    listenMarkerEvents(marker, model, leafletScope, watchOptions.individual.type, map);
4252                    leafletMarkerEvents.bindEvents(mapId, marker, pathToMarker, model, leafletScope, layerName);
4253                } else {
4254                    var oldModel = getModelFromModels(oldModels, newName, maybeLayerName);
4255                    updateMarker(model, oldModel, maybeLMarker, pathToMarker, leafletScope, layers, map);
4256                }
4257            });
4258        });
4259    };
4260    var _seeWhatWeAlreadyHave = function _seeWhatWeAlreadyHave(markerModels, oldMarkerModels, lMarkers, isEqual, cb) {
4261        var hasLogged = false,
4262            equals = false,
4263            oldMarker,
4264            newMarker;
4265
4266        var doCheckOldModel = isDefined(oldMarkerModels);
4267        for (var name in lMarkers) {
4268            if (!hasLogged) {
4269                $log.debug(errorHeader + "[markers] destroy: ");
4270                hasLogged = true;
4271            }
4272
4273            if (doCheckOldModel) {
4274                //might want to make the option (in watch options) to disable deep checking
4275                //ie the options to only check !== (reference check) instead of angular.equals (slow)
4276                newMarker = markerModels[name];
4277                oldMarker = oldMarkerModels[name];
4278                equals = isEqual && angular.equals(newMarker, oldMarker);
4279            }
4280            if (!isDefined(markerModels) || !Object.keys(markerModels).length || !isDefined(markerModels[name]) || !Object.keys(markerModels[name]).length || equals) {
4281                if (cb && Helpers.isFunction(cb)) cb(newMarker, oldMarker, name);
4282            }
4283        }
4284    };
4285    var _destroy = function _destroy(markerModels, oldMarkerModels, lMarkers, map, layers) {
4286        _seeWhatWeAlreadyHave(markerModels, oldMarkerModels, lMarkers, false, function (newMarker, oldMarker, lMarkerName) {
4287            $log.debug(errorHeader + '[marker] is deleting marker: ' + lMarkerName);
4288            deleteMarker(lMarkers[lMarkerName], map, layers);
4289            delete lMarkers[lMarkerName];
4290        });
4291    };
4292
4293    var _getNewModelsToSkipp = function _getNewModelsToSkipp(newModels, oldModels, lMarkers) {
4294        var skips = {};
4295        _seeWhatWeAlreadyHave(newModels, oldModels, lMarkers, true, function (newMarker, oldMarker, lMarkerName) {
4296            $log.debug(errorHeader + '[marker] is already rendered, marker: ' + lMarkerName);
4297            skips[lMarkerName] = newMarker;
4298        });
4299        return skips;
4300    };
4301
4302    return {
4303        restrict: "A",
4304        scope: false,
4305        replace: false,
4306        require: ['leaflet', '?layers'],
4307
4308        link: function link(scope, element, attrs, controller) {
4309            var mapController = controller[0],
4310                leafletScope = mapController.getLeafletScope();
4311
4312            mapController.getMap().then(function (map) {
4313                var leafletMarkers = {},
4314                    getLayers;
4315
4316                // If the layers attribute is used, we must wait until the layers are created
4317                if (isDefined(controller[1])) {
4318                    getLayers = controller[1].getLayers;
4319                } else {
4320                    getLayers = function getLayers() {
4321                        var deferred = $q.defer();
4322                        deferred.resolve();
4323                        return deferred.promise;
4324                    };
4325                }
4326
4327                var watchOptions;
4328                if (leafletScope.watchOptions && leafletScope.watchOptions.markers) {
4329                    watchOptions = leafletScope.watchOptions.markers;
4330                } else {
4331                    watchOptions = _defaultWatchOptions;
4332                }
4333
4334                var isNested = isDefined(attrs.markersNested) && Helpers.isTruthy(attrs.markersNested);
4335
4336                getLayers().then(function (layers) {
4337                    var _clean = function _clean(models, oldModels) {
4338                        resetUnusedMarkerGroups();
4339                        if (isNested) {
4340                            $it.each(models, function (markerToMaybeDel, layerName) {
4341                                var oldLayerModels = getLayerModels(oldModels, layerName);
4342                                _destroy(markerToMaybeDel, oldLayerModels, leafletMarkers[layerName], map, layers);
4343                            });
4344                            return;
4345                        }
4346                        _destroy(models, oldModels, leafletMarkers, map, layers);
4347                    };
4348
4349                    var _create = function _create(models, oldModels) {
4350                        _clean(models, oldModels);
4351                        var skips = null;
4352                        if (isNested) {
4353                            $it.each(models, function (markersToAdd, layerName) {
4354                                var oldLayerModels = getLayerModels(oldModels, layerName);
4355                                var newlayerModels = getLayerModels(models, layerName);
4356                                skips = _getNewModelsToSkipp(newlayerModels, oldLayerModels, leafletMarkers[layerName]);
4357                                _addMarkers(attrs.id, markersToAdd, oldModels, map, layers, leafletMarkers, leafletScope, watchOptions, layerName, skips);
4358                            });
4359                            return;
4360                        }
4361                        skips = _getNewModelsToSkipp(models, oldModels, leafletMarkers);
4362                        _addMarkers(attrs.id, models, oldModels, map, layers, leafletMarkers, leafletScope, watchOptions, undefined, skips);
4363                    };
4364                    extendDirectiveControls(attrs.id, 'markers', _create, _clean);
4365                    leafletData.setMarkers(leafletMarkers, attrs.id);
4366
4367                    maybeWatch(leafletScope, 'markers', watchOptions, function (newMarkers, oldMarkers) {
4368                        if (watchTrap.changeFromDirective) return;
4369                        _create(newMarkers, oldMarkers);
4370                    });
4371                    scope.$on('$destroy', function () {
4372                        _destroy(leafletScope.markers, {}, leafletMarkers, map, layers);
4373                    });
4374                });
4375            });
4376        }
4377    };
4378});
4379
4380'use strict';
4381
4382angular.module('ui-leaflet').directive('maxbounds', function (leafletLogger, leafletMapDefaults, leafletBoundsHelpers, leafletHelpers) {
4383    // var $log = leafletLogger;
4384    return {
4385        restrict: "A",
4386        scope: false,
4387        replace: false,
4388        require: 'leaflet',
4389
4390        link: function link(scope, element, attrs, controller) {
4391            var leafletScope = controller.getLeafletScope(),
4392                isValidBounds = leafletBoundsHelpers.isValidBounds,
4393                isNumber = leafletHelpers.isNumber;
4394
4395            controller.getMap().then(function (map) {
4396                leafletScope.$watch("maxbounds", function (maxbounds) {
4397                    if (!isValidBounds(maxbounds)) {
4398                        // Unset any previous maxbounds
4399                        map.setMaxBounds();
4400                        return;
4401                    }
4402
4403                    var leafletBounds = leafletBoundsHelpers.createLeafletBounds(maxbounds);
4404                    if (isNumber(maxbounds.pad)) {
4405                        leafletBounds = leafletBounds.pad(maxbounds.pad);
4406                    }
4407
4408                    map.setMaxBounds(leafletBounds);
4409                    if (!attrs.center && !attrs.lfCenter) {
4410                        map.fitBounds(leafletBounds);
4411                    }
4412                });
4413            });
4414        }
4415    };
4416});
4417
4418'use strict';
4419
4420angular.module('ui-leaflet').directive('paths', function (leafletLogger, $q, leafletData, leafletMapDefaults, leafletHelpers, leafletPathsHelpers, leafletPathEvents, leafletWatchHelpers) {
4421    var $log = leafletLogger;
4422    return {
4423        restrict: "A",
4424        scope: false,
4425        replace: false,
4426        require: ['leaflet', '?layers'],
4427
4428        link: function link(scope, element, attrs, controller) {
4429            var mapController = controller[0],
4430                isDefined = leafletHelpers.isDefined,
4431                isString = leafletHelpers.isString,
4432                leafletScope = mapController.getLeafletScope(),
4433                paths = leafletScope.paths,
4434                createPath = leafletPathsHelpers.createPath,
4435                bindPathEvents = leafletPathEvents.bindPathEvents,
4436                setPathOptions = leafletPathsHelpers.setPathOptions,
4437                maybeWatch = leafletWatchHelpers.maybeWatch;
4438
4439            mapController.getMap().then(function (map) {
4440                var defaults = leafletMapDefaults.getDefaults(attrs.id),
4441                    getLayers;
4442
4443                // If the layers attribute is used, we must wait until the layers are created
4444                if (isDefined(controller[1])) {
4445                    getLayers = controller[1].getLayers;
4446                } else {
4447                    getLayers = function getLayers() {
4448                        var deferred = $q.defer();
4449                        deferred.resolve();
4450                        return deferred.promise;
4451                    };
4452                }
4453
4454                if (!isDefined(paths)) {
4455                    return;
4456                }
4457
4458                //legacy behaviour does a watch collection on the paths
4459                var _legacyWatchOptions = {
4460                    type: 'watchCollection',
4461                    individual: {
4462                        type: 'watchDeep'
4463                    }
4464                };
4465
4466                var watchOptions;
4467                if (leafletScope.watchOptions && leafletScope.watchOptions.paths) {
4468                    watchOptions = leafletScope.watchOptions.paths;
4469                } else {
4470                    watchOptions = _legacyWatchOptions;
4471                }
4472
4473                getLayers().then(function (layers) {
4474
4475                    var leafletPaths = {};
4476                    leafletData.setPaths(leafletPaths, attrs.id);
4477
4478                    // Function for listening every single path once created
4479                    var watchPathFn = function watchPathFn(leafletPath, name, watchOptions) {
4480                        var pathWatchPath = "paths[\"" + name + "\"]";
4481
4482                        maybeWatch(leafletScope, pathWatchPath, watchOptions, function (pathData, old, clearWatch) {
4483                            if (!isDefined(pathData)) {
4484                                if (isDefined(old.layer)) {
4485                                    for (var i in layers.overlays) {
4486                                        var overlay = layers.overlays[i];
4487                                        overlay.removeLayer(leafletPath);
4488                                    }
4489                                }
4490                                map.removeLayer(leafletPath);
4491                                clearWatch();
4492                                return;
4493                            }
4494                            setPathOptions(leafletPath, pathData.type, pathData);
4495                        });
4496                    };
4497
4498                    var _clean = function _clean(newPaths) {
4499                        // Delete paths (by name) from the array
4500                        for (var name in leafletPaths) {
4501                            if (!isDefined(newPaths[name])) {
4502                                map.removeLayer(leafletPaths[name]);
4503                                delete leafletPaths[name];
4504                            }
4505                        }
4506                    };
4507
4508                    var _create = function _create(newPaths) {
4509                        _clean(newPaths);
4510                        // Create the new paths
4511                        for (var newName in newPaths) {
4512                            if (newName.search('\\$') === 0) {
4513                                continue;
4514                            }
4515                            if (newName.search("-") !== -1) {
4516                                $log.error('[AngularJS - Leaflet] The path name "' + newName + '" is not valid. It must not include "-" and a number.');
4517                                continue;
4518                            }
4519
4520                            if (!isDefined(leafletPaths[newName])) {
4521                                var pathData = newPaths[newName];
4522                                var newPath = createPath(newName, newPaths[newName], defaults);
4523
4524                                // bind popup if defined
4525                                if (isDefined(newPath) && isDefined(pathData.message)) {
4526                                    newPath.bindPopup(pathData.message, pathData.popupOptions);
4527                                }
4528
4529                                // Show label if defined
4530                                if (leafletHelpers.LabelPlugin.isLoaded() && isDefined(pathData.label) && isDefined(pathData.label.message)) {
4531                                    newPath.bindLabel(pathData.label.message, pathData.label.options);
4532                                }
4533
4534                                // Check if the marker should be added to a layer
4535                                if (isDefined(pathData) && isDefined(pathData.layer)) {
4536
4537                                    if (!isString(pathData.layer)) {
4538                                        $log.error('[AngularJS - Leaflet] A layername must be a string');
4539                                        continue;
4540                                    }
4541                                    if (!isDefined(layers)) {
4542                                        $log.error('[AngularJS - Leaflet] You must add layers to the directive if the markers are going to use this functionality.');
4543                                        continue;
4544                                    }
4545
4546                                    if (!isDefined(layers.overlays) || !isDefined(layers.overlays[pathData.layer])) {
4547                                        $log.error('[AngularJS - Leaflet] A path can only be added to a layer of type "group"');
4548                                        continue;
4549                                    }
4550                                    var layerGroup = layers.overlays[pathData.layer];
4551                                    if (!(layerGroup instanceof L.LayerGroup || layerGroup instanceof L.FeatureGroup)) {
4552                                        $log.error('[AngularJS - Leaflet] Adding a path to an overlay needs a overlay of the type "group" or "featureGroup"');
4553                                        continue;
4554                                    }
4555
4556                                    // Listen for changes on the new path
4557                                    leafletPaths[newName] = newPath;
4558                                    // The path goes to a correct layer group, so first of all we add it
4559                                    layerGroup.addLayer(newPath);
4560
4561                                    if (watchOptions.individual.type !== null) {
4562                                        watchPathFn(newPath, newName, watchOptions.individual);
4563                                    } else {
4564                                        setPathOptions(newPath, pathData.type, pathData);
4565                                    }
4566                                } else if (isDefined(newPath)) {
4567                                    // Listen for changes on the new path
4568                                    leafletPaths[newName] = newPath;
4569                                    map.addLayer(newPath);
4570
4571                                    if (watchOptions.individual.type !== null) {
4572                                        watchPathFn(newPath, newName, watchOptions.individual);
4573                                    } else {
4574                                        setPathOptions(newPath, pathData.type, pathData);
4575                                    }
4576                                }
4577
4578                                bindPathEvents(attrs.id, newPath, newName, pathData, leafletScope);
4579                            }
4580                        }
4581                    };
4582
4583                    maybeWatch(leafletScope, 'paths', watchOptions, function (newPaths) {
4584                        _create(newPaths);
4585                    });
4586                });
4587            });
4588        }
4589    };
4590});
4591
4592'use strict';
4593
4594angular.module('ui-leaflet').directive('tiles', function (leafletLogger, leafletData, leafletMapDefaults, leafletHelpers) {
4595    var $log = leafletLogger;
4596    return {
4597        restrict: "A",
4598        scope: false,
4599        replace: false,
4600        require: 'leaflet',
4601
4602        link: function link(scope, element, attrs, controller) {
4603            var isDefined = leafletHelpers.isDefined,
4604                leafletScope = controller.getLeafletScope(),
4605                tiles = leafletScope.tiles;
4606
4607            if (!isDefined(tiles) || !isDefined(tiles.url)) {
4608                $log.warn("[AngularJS - Leaflet] The 'tiles' definition doesn't have the 'url' property.");
4609                return;
4610            }
4611
4612            controller.getMap().then(function (map) {
4613                var defaults = leafletMapDefaults.getDefaults(attrs.id);
4614                var tileLayerObj;
4615                leafletScope.$watch("tiles", function (tiles) {
4616                    var tileLayerOptions = defaults.tileLayerOptions;
4617                    var tileLayerUrl = defaults.tileLayer;
4618
4619                    // If no valid tiles are in the scope, remove the last layer
4620                    if (!isDefined(tiles.url) && isDefined(tileLayerObj)) {
4621                        map.removeLayer(tileLayerObj);
4622                        return;
4623                    }
4624
4625                    // No leafletTiles object defined yet
4626                    if (!isDefined(tileLayerObj)) {
4627                        if (isDefined(tiles.options)) {
4628                            angular.copy(tiles.options, tileLayerOptions);
4629                        }
4630
4631                        if (isDefined(tiles.url)) {
4632                            tileLayerUrl = tiles.url;
4633                        }
4634
4635                        tileLayerObj = L.tileLayer(tileLayerUrl, tileLayerOptions);
4636                        tileLayerObj.addTo(map);
4637                        leafletData.setTiles(tileLayerObj, attrs.id);
4638                        return;
4639                    }
4640
4641                    // If the options of the tilelayer is changed, we need to redraw the layer
4642                    if (isDefined(tiles.url) && isDefined(tiles.options) && !angular.equals(tiles.options, tileLayerOptions)) {
4643                        map.removeLayer(tileLayerObj);
4644                        tileLayerOptions = defaults.tileLayerOptions;
4645                        angular.copy(tiles.options, tileLayerOptions);
4646                        tileLayerUrl = tiles.url;
4647                        tileLayerObj = L.tileLayer(tileLayerUrl, tileLayerOptions);
4648                        tileLayerObj.addTo(map);
4649                        leafletData.setTiles(tileLayerObj, attrs.id);
4650                        return;
4651                    }
4652
4653                    // Only the URL of the layer is changed, update the tiles object
4654                    if (isDefined(tiles.url)) {
4655                        tileLayerObj.setUrl(tiles.url);
4656                    }
4657                }, true);
4658            });
4659        }
4660    };
4661});
4662
4663'use strict';
4664
4665angular.module('ui-leaflet').directive('watchOptions', ['$log', '$rootScope', '$q', 'leafletData', 'leafletHelpers', function (leafletLogger, $rootScope, $q, leafletData, leafletHelpers) {
4666
4667    var isDefined = leafletHelpers.isDefined,
4668        errorHeader = leafletHelpers.errorHeader,
4669        isObject = leafletHelpers.isObject,
4670        $log = leafletLogger;
4671
4672    return {
4673        restrict: "A",
4674        scope: false,
4675        replace: false,
4676        require: ['leaflet'],
4677
4678        link: function link(scope, element, attrs, controller) {
4679            var mapController = controller[0],
4680                leafletScope = mapController.getLeafletScope();
4681
4682            var _isValidWatchType = function _isValidWatchType(type) {
4683                return type === 'watch' || type === 'watchCollection' || type === 'watchDeep' || type === null;
4684            };
4685
4686            if (isDefined(leafletScope.watchOptions) && isObject(leafletScope.watchOptions)) {
4687                angular.forEach(['markers', 'geojson', 'paths'], function (name) {
4688                    if (isDefined(leafletScope.watchOptions[name])) {
4689                        if (!_isValidWatchType(leafletScope.watchOptions[name].type)) {
4690                            $log.error(errorHeader + ' watchOptions.' + name + '.type is not a valid type.');
4691                        }
4692                        if (isDefined(leafletScope.watchOptions[name].individual)) {
4693                            if (!_isValidWatchType(leafletScope.watchOptions[name].individual.type)) {
4694                                $log.error(errorHeader + ' watchOptions.' + name + '.individual.type is not a valid type.');
4695                            }
4696                        } else {
4697                            $log.error(errorHeader + ' watchOptions.' + name + '.type.individual must be defined.');
4698                        }
4699                    }
4700                });
4701            }
4702        }
4703    };
4704}]);
4705
4706'use strict';
4707
4708angular.module('ui-leaflet').factory('leafletEventsHelpersFactory', function ($rootScope, $q, leafletLogger, leafletHelpers) {
4709    var safeApply = leafletHelpers.safeApply,
4710        isDefined = leafletHelpers.isDefined,
4711        isObject = leafletHelpers.isObject,
4712        isArray = leafletHelpers.isArray,
4713        errorHeader = leafletHelpers.errorHeader,
4714        $log = leafletLogger;
4715
4716    var EventsHelper = function EventsHelper(rootBroadcastName, lObjectType) {
4717        this.rootBroadcastName = rootBroadcastName;
4718        $log.debug("leafletEventsHelpersFactory: lObjectType: " + lObjectType + "rootBroadcastName: " + rootBroadcastName);
4719        //used to path/key out certain properties based on the type , "markers", "geojson"
4720        this.lObjectType = lObjectType;
4721    };
4722
4723    EventsHelper.prototype.getAvailableEvents = function () {
4724        return [];
4725    };
4726
4727    /*
4728     argument: name: Note this can be a single string or dot notation
4729     Example:
4730     markerModel : {
4731     m1: { lat:_, lon: _}
4732     }
4733     //would yield name of
4734     name = "m1"
4735      If nested:
4736     markerModel : {
4737     cars: {
4738     m1: { lat:_, lon: _}
4739     }
4740     }
4741     //would yield name of
4742     name = "cars.m1"
4743     */
4744    EventsHelper.prototype.genDispatchEvent = function (maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName, extra) {
4745        var _this = this;
4746
4747        maybeMapId = maybeMapId || '';
4748        if (maybeMapId) maybeMapId = '.' + maybeMapId;
4749
4750        return function (e) {
4751            var broadcastName = _this.rootBroadcastName + maybeMapId + '.' + eventName;
4752            $log.debug(broadcastName);
4753            _this.fire(leafletScope, broadcastName, logic, e, e.target || lObject, model, name, layerName, extra);
4754        };
4755    };
4756
4757    EventsHelper.prototype.fire = function (scope, broadcastName, logic, event, lObject, model, modelName, layerName, extra) {
4758        // Safely broadcast the event
4759        safeApply(scope, function () {
4760            var toSend = {
4761                leafletEvent: event,
4762                leafletObject: lObject,
4763                modelName: modelName,
4764                model: model
4765            };
4766            if (isDefined(layerName)) angular.extend(toSend, { layerName: layerName });
4767
4768            if (logic === "emit") {
4769                scope.$emit(broadcastName, toSend);
4770            } else {
4771                $rootScope.$broadcast(broadcastName, toSend);
4772            }
4773        });
4774    };
4775
4776    EventsHelper.prototype.bindEvents = function (maybeMapId, lObject, name, model, leafletScope, layerName, extra) {
4777        var events = [];
4778        var logic = 'emit';
4779        var _this = this;
4780
4781        if (!isDefined(leafletScope.eventBroadcast)) {
4782            // Backward compatibility, if no event-broadcast attribute, all events are broadcasted
4783            events = this.getAvailableEvents();
4784        } else if (!isObject(leafletScope.eventBroadcast)) {
4785            // Not a valid object
4786            $log.error(errorHeader + "event-broadcast must be an object check your model.");
4787        } else {
4788            // We have a possible valid object
4789            if (!isDefined(leafletScope.eventBroadcast[_this.lObjectType])) {
4790                // We do not have events enable/disable do we do nothing (all enabled by default)
4791                events = this.getAvailableEvents();
4792            } else if (!isObject(leafletScope.eventBroadcast[_this.lObjectType])) {
4793                // Not a valid object
4794                $log.warn(errorHeader + 'event-broadcast.' + [_this.lObjectType] + ' must be an object check your model.');
4795            } else {
4796                // We have a possible valid map object
4797                // Event propadation logic
4798                if (isDefined(leafletScope.eventBroadcast[this.lObjectType].logic)) {
4799                    // We take care of possible propagation logic
4800                    if (leafletScope.eventBroadcast[_this.lObjectType].logic !== "emit" && leafletScope.eventBroadcast[_this.lObjectType].logic !== "broadcast") $log.warn(errorHeader + "Available event propagation logic are: 'emit' or 'broadcast'.");
4801                }
4802                // Enable / Disable
4803                var eventsEnable = false,
4804                    eventsDisable = false;
4805                if (isDefined(leafletScope.eventBroadcast[_this.lObjectType].enable) && isArray(leafletScope.eventBroadcast[_this.lObjectType].enable)) eventsEnable = true;
4806                if (isDefined(leafletScope.eventBroadcast[_this.lObjectType].disable) && isArray(leafletScope.eventBroadcast[_this.lObjectType].disable)) eventsDisable = true;
4807
4808                if (eventsEnable && eventsDisable) {
4809                    // Both are active, this is an error
4810                    $log.warn(errorHeader + "can not enable and disable events at the same time");
4811                } else if (!eventsEnable && !eventsDisable) {
4812                    // Both are inactive, this is an error
4813                    $log.warn(errorHeader + "must enable or disable events");
4814                } else {
4815                    // At this point the object is OK, lets enable or disable events
4816                    if (eventsEnable) {
4817                        // Enable events
4818                        leafletScope.eventBroadcast[this.lObjectType].enable.forEach(function (eventName) {
4819                            // Do we have already the event enabled?
4820                            if (events.indexOf(eventName) !== -1) {
4821                                // Repeated event, this is an error
4822                                $log.warn(errorHeader + "This event " + eventName + " is already enabled");
4823                            } else {
4824                                // Does the event exists?
4825                                if (_this.getAvailableEvents().indexOf(eventName) === -1) {
4826                                    // The event does not exists, this is an error
4827                                    $log.warn(errorHeader + "This event " + eventName + " does not exist");
4828                                } else {
4829                                    // All ok enable the event
4830                                    events.push(eventName);
4831                                }
4832                            }
4833                        });
4834                    } else {
4835                        // Disable events
4836                        events = this.getAvailableEvents();
4837                        leafletScope.eventBroadcast[_this.lObjectType].disable.forEach(function (eventName) {
4838                            var index = events.indexOf(eventName);
4839                            if (index === -1) {
4840                                // The event does not exist
4841                                $log.warn(errorHeader + "This event " + eventName + " does not exist or has been already disabled");
4842                            } else {
4843                                events.splice(index, 1);
4844                            }
4845                        });
4846                    }
4847                }
4848            }
4849        }
4850
4851        events.forEach(function (eventName) {
4852            lObject.on(eventName, _this.genDispatchEvent(maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName, extra));
4853        });
4854        return logic;
4855    };
4856
4857    return EventsHelper;
4858}).service('leafletEventsHelpers', function (leafletEventsHelpersFactory) {
4859    return new leafletEventsHelpersFactory();
4860});
4861
4862'use strict';
4863
4864angular.module('ui-leaflet').factory('leafletGeoJsonEvents', function ($rootScope, $q, leafletLogger, leafletHelpers, leafletEventsHelpersFactory, leafletData) {
4865    var safeApply = leafletHelpers.safeApply,
4866        EventsHelper = leafletEventsHelpersFactory;
4867    // $log = leafletLogger;
4868
4869    var GeoJsonEvents = function GeoJsonEvents() {
4870        EventsHelper.call(this, 'leafletDirectiveGeoJson', 'geojson');
4871    };
4872
4873    GeoJsonEvents.prototype = new EventsHelper();
4874
4875    GeoJsonEvents.prototype.genDispatchEvent = function (maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName, extra) {
4876        var base = EventsHelper.prototype.genDispatchEvent.call(this, maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName),
4877            _this = this;
4878
4879        return function (e) {
4880            if (eventName === 'mouseout') {
4881                if (extra.resetStyleOnMouseout) {
4882                    leafletData.getGeoJSON(extra.mapId).then(function (leafletGeoJSON) {
4883                        //this is broken on nested needs to traverse or user layerName (nested)
4884                        var lobj = layerName ? leafletGeoJSON[layerName] : leafletGeoJSON;
4885                        lobj.resetStyle(e.target);
4886                    });
4887                }
4888                safeApply(leafletScope, function () {
4889                    $rootScope.$broadcast(_this.rootBroadcastName + '.mouseout', e);
4890                });
4891            }
4892            base(e); //common
4893        };
4894    };
4895
4896    GeoJsonEvents.prototype.getAvailableEvents = function () {
4897        return ['click', 'dblclick', 'mouseover', 'mouseout'];
4898    };
4899
4900    return new GeoJsonEvents();
4901});
4902
4903'use strict';
4904
4905angular.module('ui-leaflet').factory('leafletLabelEvents', function ($rootScope, $q, leafletLogger, leafletHelpers, leafletEventsHelpersFactory) {
4906    var Helpers = leafletHelpers,
4907        EventsHelper = leafletEventsHelpersFactory;
4908    //$log = leafletLogger;
4909
4910    var LabelEvents = function LabelEvents() {
4911        EventsHelper.call(this, 'leafletDirectiveLabel', 'markers');
4912    };
4913    LabelEvents.prototype = new EventsHelper();
4914
4915    LabelEvents.prototype.genDispatchEvent = function (maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName) {
4916        var markerName = name.replace('markers.', '');
4917        return EventsHelper.prototype.genDispatchEvent.call(this, maybeMapId, eventName, logic, leafletScope, lObject, markerName, model, layerName);
4918    };
4919
4920    LabelEvents.prototype.getAvailableEvents = function () {
4921        return ['click', 'dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu'];
4922    };
4923
4924    LabelEvents.prototype.genEvents = function (maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName) {
4925        var _this = this;
4926        var labelEvents = this.getAvailableEvents();
4927        var scopeWatchName = Helpers.getObjectArrayPath("markers." + name);
4928        labelEvents.forEach(function (eventName) {
4929            lObject.label.on(eventName, _this.genDispatchEvent(maybeMapId, eventName, logic, leafletScope, lObject.label, scopeWatchName, model, layerName));
4930        });
4931    };
4932
4933    LabelEvents.prototype.bindEvents = function (maybeMapId, lObject, name, model, leafletScope, layerName) {};
4934
4935    return new LabelEvents();
4936});
4937
4938'use strict';
4939
4940angular.module('ui-leaflet').factory('leafletMapEvents', function ($rootScope, $q, leafletLogger, leafletHelpers, leafletEventsHelpers, leafletIterators) {
4941    var isDefined = leafletHelpers.isDefined,
4942        fire = leafletEventsHelpers.fire;
4943
4944    var _getAvailableMapEvents = function _getAvailableMapEvents() {
4945        return ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'mousemove', 'contextmenu', 'focus', 'blur', 'preclick', 'load', 'unload', 'viewreset', 'movestart', 'move', 'moveend', 'dragstart', 'drag', 'dragend', 'zoomstart', 'zoomanim', 'zoomend', 'zoomlevelschange', 'resize', 'autopanstart', 'layeradd', 'layerremove', 'baselayerchange', 'overlayadd', 'overlayremove', 'locationfound', 'locationerror', 'popupopen', 'popupclose', 'draw:created', 'draw:edited', 'draw:deleted', 'draw:drawstart', 'draw:drawstop', 'draw:editstart', 'draw:editstop', 'draw:deletestart', 'draw:deletestop'];
4946    };
4947
4948    var _genDispatchMapEvent = function _genDispatchMapEvent(scope, eventName, logic, maybeMapId) {
4949        if (maybeMapId) {
4950            maybeMapId = maybeMapId + '.';
4951        }
4952        return function (e) {
4953            // Put together broadcast name
4954            var broadcastName = 'leafletDirectiveMap.' + maybeMapId + eventName;
4955            leafletLogger.debug(broadcastName);
4956            // Safely broadcast the event
4957            fire(scope, broadcastName, logic, e, e.target, scope);
4958        };
4959    };
4960
4961    var _notifyCenterChangedToBounds = function _notifyCenterChangedToBounds(scope) {
4962        scope.$broadcast("boundsChanged");
4963    };
4964
4965    var _notifyCenterUrlHashChanged = function _notifyCenterUrlHashChanged(scope, map, attrs, search) {
4966        if (!isDefined(attrs.urlHashCenter)) {
4967            return;
4968        }
4969        var center = map.getCenter();
4970        var centerUrlHash = center.lat.toFixed(4) + ":" + center.lng.toFixed(4) + ":" + map.getZoom();
4971        if (!isDefined(search.c) || search.c !== centerUrlHash) {
4972            //$log.debug("notified new center...");
4973            scope.$emit("centerUrlHash", centerUrlHash);
4974        }
4975    };
4976
4977    var _addEvents = function _addEvents(map, mapId, mapEvents, contextName, scope, logic) {
4978        leafletIterators.each(mapEvents, function (eventName) {
4979            var context = {};
4980            context[contextName] = eventName;
4981            if (!mapId) {
4982                mapId = map._container.id || '';
4983            }
4984
4985            map.on(eventName, _genDispatchMapEvent(scope, eventName, logic, mapId), context);
4986        });
4987    };
4988
4989    return {
4990        getAvailableMapEvents: _getAvailableMapEvents,
4991        genDispatchMapEvent: _genDispatchMapEvent,
4992        notifyCenterChangedToBounds: _notifyCenterChangedToBounds,
4993        notifyCenterUrlHashChanged: _notifyCenterUrlHashChanged,
4994        addEvents: _addEvents
4995    };
4996});
4997
4998'use strict';
4999
5000angular.module('ui-leaflet').factory('leafletMarkerEvents', function ($rootScope, $q, leafletLogger, leafletHelpers, leafletEventsHelpersFactory, leafletLabelEvents) {
5001    var safeApply = leafletHelpers.safeApply,
5002        isDefined = leafletHelpers.isDefined,
5003        Helpers = leafletHelpers,
5004        lblHelp = leafletLabelEvents,
5005        EventsHelper = leafletEventsHelpersFactory,
5006        $log = leafletLogger;
5007
5008    var MarkerEvents = function MarkerEvents() {
5009        EventsHelper.call(this, 'leafletDirectiveMarker', 'markers');
5010    };
5011
5012    MarkerEvents.prototype = new EventsHelper();
5013
5014    MarkerEvents.prototype.genDispatchEvent = function (maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName) {
5015        var handle = EventsHelper.prototype.genDispatchEvent.call(this, maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName);
5016        return function (e) {
5017            // Broadcast old marker click name for backwards compatibility
5018            if (eventName === "click") {
5019                safeApply(leafletScope, function () {
5020                    $rootScope.$broadcast('leafletDirectiveMarkersClick', name);
5021                });
5022            } else if (eventName === 'dragend') {
5023                safeApply(leafletScope, function () {
5024                    model.lat = lObject.getLatLng().lat;
5025                    model.lng = lObject.getLatLng().lng;
5026                });
5027                if (model.message && model.focus === true) {
5028                    lObject.openPopup();
5029                }
5030            }
5031            handle(e); //common
5032        };
5033    };
5034
5035    MarkerEvents.prototype.getAvailableEvents = function () {
5036        return ['click', 'dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu', 'dragstart', 'drag', 'dragend', 'move', 'remove', 'popupopen', 'popupclose', 'touchend', 'touchstart', 'touchmove', 'touchcancel', 'touchleave'];
5037    };
5038
5039    MarkerEvents.prototype.bindEvents = function (maybeMapId, lObject, name, model, leafletScope, layerName) {
5040        var logic = EventsHelper.prototype.bindEvents.call(this, maybeMapId, lObject, name, model, leafletScope, layerName);
5041
5042        if (Helpers.LabelPlugin.isLoaded() && isDefined(lObject.label)) {
5043            lblHelp.genEvents(maybeMapId, name, logic, leafletScope, lObject, model, layerName);
5044        }
5045    };
5046
5047    return new MarkerEvents();
5048});
5049
5050'use strict';
5051
5052var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
5053
5054angular.module('ui-leaflet').factory('leafletPathEvents', function ($rootScope, $q, leafletLogger, leafletHelpers, leafletLabelEvents, leafletEventsHelpers) {
5055    var isDefined = leafletHelpers.isDefined,
5056        isObject = leafletHelpers.isObject,
5057        Helpers = leafletHelpers,
5058        errorHeader = leafletHelpers.errorHeader,
5059        lblHelp = leafletLabelEvents,
5060        fire = leafletEventsHelpers.fire,
5061        $log = leafletLogger;
5062
5063    /*
5064    TODO (nmccready) This EventsHelper needs to be derrived from leafletEventsHelpers to elminate copy and paste code.
5065    */
5066
5067    var _genDispatchPathEvent = function _genDispatchPathEvent(maybeMapId, eventName, logic, leafletScope, lObject, name, model, layerName) {
5068        maybeMapId = maybeMapId || '';
5069
5070        if (maybeMapId) maybeMapId = '.' + maybeMapId;
5071
5072        return function (e) {
5073            var broadcastName = 'leafletDirectivePath' + maybeMapId + '.' + eventName;
5074            $log.debug(broadcastName);
5075            fire(leafletScope, broadcastName, logic, e, e.target || lObject, model, name, layerName);
5076        };
5077    };
5078
5079    var _bindPathEvents = function _bindPathEvents(maybeMapId, lObject, name, model, leafletScope) {
5080        var pathEvents = [],
5081            i,
5082            eventName,
5083            logic = "broadcast";
5084
5085        if (!isDefined(leafletScope.eventBroadcast)) {
5086            // Backward compatibility, if no event-broadcast attribute, all events are broadcasted
5087            pathEvents = _getAvailablePathEvents();
5088        } else if (!isObject(leafletScope.eventBroadcast)) {
5089            // Not a valid object
5090            $log.error(errorHeader + "event-broadcast must be an object check your model.");
5091        } else {
5092            // We have a possible valid object
5093            if (!isDefined(leafletScope.eventBroadcast.path)) {
5094                // We do not have events enable/disable do we do nothing (all enabled by default)
5095                pathEvents = _getAvailablePathEvents();
5096            } else if (isObject(leafletScope.eventBroadcast.paths)) {
5097                // Not a valid object
5098                $log.warn(errorHeader + "event-broadcast.path must be an object check your model.");
5099            } else {
5100                // We have a possible valid map object
5101                // Event propadation logic
5102                if (leafletScope.eventBroadcast.path.logic !== undefined && leafletScope.eventBroadcast.path.logic !== null) {
5103                    // We take care of possible propagation logic
5104                    if (leafletScope.eventBroadcast.path.logic !== "emit" && leafletScope.eventBroadcast.path.logic !== "broadcast") {
5105                        // This is an error
5106                        $log.warn(errorHeader + "Available event propagation logic are: 'emit' or 'broadcast'.");
5107                    } else if (leafletScope.eventBroadcast.path.logic === "emit") {
5108                        logic = "emit";
5109                    }
5110                }
5111                // Enable / Disable
5112                var pathEventsEnable = false,
5113                    pathEventsDisable = false;
5114                if (leafletScope.eventBroadcast.path.enable !== undefined && leafletScope.eventBroadcast.path.enable !== null) {
5115                    if (_typeof(leafletScope.eventBroadcast.path.enable) === 'object') {
5116                        pathEventsEnable = true;
5117                    }
5118                }
5119                if (leafletScope.eventBroadcast.path.disable !== undefined && leafletScope.eventBroadcast.path.disable !== null) {
5120                    if (_typeof(leafletScope.eventBroadcast.path.disable) === 'object') {
5121                        pathEventsDisable = true;
5122                    }
5123                }
5124                if (pathEventsEnable && pathEventsDisable) {
5125                    // Both are active, this is an error
5126                    $log.warn(errorHeader + "can not enable and disable events at the same time");
5127                } else if (!pathEventsEnable && !pathEventsDisable) {
5128                    // Both are inactive, this is an error
5129                    $log.warn(errorHeader + "must enable or disable events");
5130                } else {
5131                    // At this point the path object is OK, lets enable or disable events
5132                    if (pathEventsEnable) {
5133                        // Enable events
5134                        for (i = 0; i < leafletScope.eventBroadcast.path.enable.length; i++) {
5135                            eventName = leafletScope.eventBroadcast.path.enable[i];
5136                            // Do we have already the event enabled?
5137                            if (pathEvents.indexOf(eventName) !== -1) {
5138                                // Repeated event, this is an error
5139                                $log.warn(errorHeader + "This event " + eventName + " is already enabled");
5140                            } else {
5141                                // Does the event exists?
5142                                if (_getAvailablePathEvents().indexOf(eventName) === -1) {
5143                                    // The event does not exists, this is an error
5144                                    $log.warn(errorHeader + "This event " + eventName + " does not exist");
5145                                } else {
5146                                    // All ok enable the event
5147                                    pathEvents.push(eventName);
5148                                }
5149                            }
5150                        }
5151                    } else {
5152                        // Disable events
5153                        pathEvents = _getAvailablePathEvents();
5154                        for (i = 0; i < leafletScope.eventBroadcast.path.disable.length; i++) {
5155                            eventName = leafletScope.eventBroadcast.path.disable[i];
5156                            var index = pathEvents.indexOf(eventName);
5157                            if (index === -1) {
5158                                // The event does not exist
5159                                $log.warn(errorHeader + "This event " + eventName + " does not exist or has been already disabled");
5160                            } else {
5161                                pathEvents.splice(index, 1);
5162                            }
5163                        }
5164                    }
5165                }
5166            }
5167        }
5168
5169        for (i = 0; i < pathEvents.length; i++) {
5170            eventName = pathEvents[i];
5171            lObject.on(eventName, _genDispatchPathEvent(maybeMapId, eventName, logic, leafletScope, pathEvents, name));
5172        }
5173
5174        if (Helpers.LabelPlugin.isLoaded() && isDefined(lObject.label)) {
5175            lblHelp.genEvents(maybeMapId, name, logic, leafletScope, lObject, model);
5176        }
5177    };
5178
5179    var _getAvailablePathEvents = function _getAvailablePathEvents() {
5180        return ['click', 'dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu', 'add', 'remove', 'popupopen', 'popupclose'];
5181    };
5182
5183    return {
5184        getAvailablePathEvents: _getAvailablePathEvents,
5185        bindPathEvents: _bindPathEvents
5186    };
5187});
5188
5189}(angular));
5190//# sourceMappingURL=ui-leaflet_dev_mapped.js.map