leaflet-rails 0.4.0.alpha2 → 0.4.0alpha3

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,40 +3,26 @@
3
3
  Leaflet is a modern open-source JavaScript library for interactive maps.
4
4
  http://leaflet.cloudmade.com
5
5
  */
6
+ (function () {
6
7
 
7
- (function (root) {
8
- root.L = {
9
- VERSION: '0.4',
10
-
11
- ROOT_URL: root.L_ROOT_URL || (function () {
12
- var scripts = document.getElementsByTagName('script'),
13
- leafletRe = /\/?leaflet[\-\._]?([\w\-\._]*)\.js\??/;
14
-
15
- var i, len, src, matches;
16
-
17
- for (i = 0, len = scripts.length; i < len; i++) {
18
- src = scripts[i].src;
19
- matches = src.match(leafletRe);
8
+ var L, originalL;
20
9
 
21
- if (matches) {
22
- if (matches[1] === 'include') {
23
- return '../../dist/';
24
- }
25
- return src.split(leafletRe)[0] + '/';
26
- }
27
- }
10
+ if (typeof exports !== 'undefined') {
11
+ L = exports;
12
+ } else {
13
+ L = {};
14
+
15
+ originalL = window.L;
28
16
 
29
- return '';
30
- }()),
17
+ L.noConflict = function () {
18
+ window.L = originalL;
19
+ return L;
20
+ };
31
21
 
32
- noConflict: function () {
33
- root.L = this._originalL;
34
- return this;
35
- },
22
+ window.L = L;
23
+ }
36
24
 
37
- _originalL: root.L
38
- };
39
- }(this));
25
+ L.version = '0.4';
40
26
 
41
27
 
42
28
  /*
@@ -57,9 +43,10 @@ L.Util = {
57
43
  return dest;
58
44
  },
59
45
 
60
- bind: function (/*Function*/ fn, /*Object*/ obj) /*-> Object*/ {
46
+ bind: function (fn, obj) { // (Function, Object) -> Function
47
+ var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null;
61
48
  return function () {
62
- return fn.apply(obj, arguments);
49
+ return fn.apply(obj, args || arguments);
63
50
  };
64
51
  },
65
52
 
@@ -111,23 +98,28 @@ L.Util = {
111
98
  }()),
112
99
 
113
100
  limitExecByInterval: function (fn, time, context) {
114
- var lock, execOnUnlock, args;
115
- function exec() {
116
- lock = false;
117
- if (execOnUnlock) {
118
- args.callee.apply(context, args);
119
- execOnUnlock = false;
120
- }
121
- }
122
- return function () {
123
- args = arguments;
124
- if (!lock) {
125
- lock = true;
126
- setTimeout(exec, time);
127
- fn.apply(context, args);
128
- } else {
101
+ var lock, execOnUnlock;
102
+
103
+ return function wrapperFn() {
104
+ var args = arguments;
105
+
106
+ if (lock) {
129
107
  execOnUnlock = true;
108
+ return;
130
109
  }
110
+
111
+ lock = true;
112
+
113
+ setTimeout(function () {
114
+ lock = false;
115
+
116
+ if (execOnUnlock) {
117
+ wrapperFn.apply(context, args);
118
+ execOnUnlock = false;
119
+ }
120
+ }, time);
121
+
122
+ fn.apply(context, args);
131
123
  };
132
124
  },
133
125
 
@@ -142,6 +134,7 @@ L.Util = {
142
134
 
143
135
  setOptions: function (obj, options) {
144
136
  obj.options = L.Util.extend({}, obj.options, options);
137
+ return obj.options;
145
138
  },
146
139
 
147
140
  getParamString: function (obj) {
@@ -186,20 +179,15 @@ L.Class.extend = function (/*Object*/ props) /*-> Class*/ {
186
179
  // instantiate class without calling constructor
187
180
  var F = function () {};
188
181
  F.prototype = this.prototype;
189
- var proto = new F();
190
182
 
183
+ var proto = new F();
191
184
  proto.constructor = NewClass;
192
- NewClass.prototype = proto;
193
185
 
194
- // add superclass access
195
- NewClass.superclass = this.prototype;
196
-
197
- // add class name
198
- //proto.className = props;
186
+ NewClass.prototype = proto;
199
187
 
200
188
  //inherit parent's statics
201
189
  for (var i in this) {
202
- if (this.hasOwnProperty(i) && i !== 'prototype' && i !== 'superclass') {
190
+ if (this.hasOwnProperty(i) && i !== 'prototype') {
203
191
  NewClass[i] = this[i];
204
192
  }
205
193
  }
@@ -224,17 +212,18 @@ L.Class.extend = function (/*Object*/ props) /*-> Class*/ {
224
212
  // mix given properties into the prototype
225
213
  L.Util.extend(proto, props);
226
214
 
227
- // allow inheriting further
228
- NewClass.extend = L.Class.extend;
215
+ return NewClass;
216
+ };
229
217
 
230
- // method for adding properties to prototype
231
- NewClass.include = function (props) {
232
- L.Util.extend(this.prototype, props);
233
- };
234
218
 
235
- return NewClass;
219
+ // method for adding properties to prototype
220
+ L.Class.include = function (props) {
221
+ L.Util.extend(this.prototype, props);
236
222
  };
237
223
 
224
+ L.Class.mergeOptions = function (options) {
225
+ L.Util.extend(this.prototype.options, options);
226
+ };
238
227
 
239
228
  /*
240
229
  * L.Mixin.Events adds custom events functionality to Leaflet classes
@@ -556,6 +545,12 @@ L.DomUtil = {
556
545
  L.DomUtil.getStyle(el, 'position') === 'absolute') {
557
546
  break;
558
547
  }
548
+ if (L.DomUtil.getStyle(el, 'position') === 'fixed') {
549
+ top += docBody.scrollTop || 0;
550
+ left += docBody.scrollLeft || 0;
551
+ break;
552
+ }
553
+
559
554
  el = el.offsetParent;
560
555
  } while (el);
561
556
 
@@ -621,7 +616,7 @@ L.DomUtil = {
621
616
 
622
617
  setOpacity: function (el, value) {
623
618
  if (L.Browser.ie) {
624
- el.style.filter = 'alpha(opacity=' + Math.round(value * 100) + ')';
619
+ el.style.filter += value !== 1 ? 'alpha(opacity=' + Math.round(value * 100) + ')' : '';
625
620
  } else {
626
621
  el.style.opacity = value;
627
622
  }
@@ -756,16 +751,21 @@ L.LatLngBounds = L.Class.extend({
756
751
  }
757
752
  },
758
753
 
759
- // extend the bounds to contain the given point
760
- extend: function (/*LatLng*/ latlng) {
761
- if (!this._southWest && !this._northEast) {
762
- this._southWest = new L.LatLng(latlng.lat, latlng.lng, true);
763
- this._northEast = new L.LatLng(latlng.lat, latlng.lng, true);
764
- } else {
765
- this._southWest.lat = Math.min(latlng.lat, this._southWest.lat);
766
- this._southWest.lng = Math.min(latlng.lng, this._southWest.lng);
767
- this._northEast.lat = Math.max(latlng.lat, this._northEast.lat);
768
- this._northEast.lng = Math.max(latlng.lng, this._northEast.lng);
754
+ // extend the bounds to contain the given point or bounds
755
+ extend: function (/*LatLng or LatLngBounds*/ obj) {
756
+ if (obj instanceof L.LatLng) {
757
+ if (!this._southWest && !this._northEast) {
758
+ this._southWest = new L.LatLng(obj.lat, obj.lng, true);
759
+ this._northEast = new L.LatLng(obj.lat, obj.lng, true);
760
+ } else {
761
+ this._southWest.lat = Math.min(obj.lat, this._southWest.lat);
762
+ this._southWest.lng = Math.min(obj.lng, this._southWest.lng);
763
+ this._northEast.lat = Math.max(obj.lat, this._northEast.lat);
764
+ this._northEast.lng = Math.max(obj.lng, this._northEast.lng);
765
+ }
766
+ } else if (obj instanceof L.LatLngBounds) {
767
+ this.extend(obj._southWest);
768
+ this.extend(obj._northEast);
769
769
  }
770
770
  return this;
771
771
  },
@@ -858,7 +858,7 @@ L.Projection = {};
858
858
  L.Projection.SphericalMercator = {
859
859
  MAX_LATITUDE: 85.0511287798,
860
860
 
861
- project: function (/*LatLng*/ latlng) /*-> Point*/ {
861
+ project: function (latlng) { // (LatLng) -> Point
862
862
  var d = L.LatLng.DEG_TO_RAD,
863
863
  max = this.MAX_LATITUDE,
864
864
  lat = Math.max(Math.min(max, latlng.lat), -max),
@@ -869,7 +869,7 @@ L.Projection.SphericalMercator = {
869
869
  return new L.Point(x, y);
870
870
  },
871
871
 
872
- unproject: function (/*Point*/ point, /*Boolean*/ unbounded) /*-> LatLng*/ {
872
+ unproject: function (point, unbounded) { // (Point, Boolean) -> LatLng
873
873
  var d = L.LatLng.RAD_TO_DEG,
874
874
  lng = point.x * d,
875
875
  lat = (2 * Math.atan(Math.exp(point.y)) - (Math.PI / 2)) * d;
@@ -893,19 +893,27 @@ L.Projection.LonLat = {
893
893
 
894
894
 
895
895
  L.CRS = {
896
- latLngToPoint: function (/*LatLng*/ latlng, /*Number*/ scale)/*-> Point*/ {
897
- var projectedPoint = this.projection.project(latlng);
896
+ latLngToPoint: function (latlng, zoom) { // (LatLng, Number) -> Point
897
+ var projectedPoint = this.projection.project(latlng),
898
+ scale = this.scale(zoom);
899
+
898
900
  return this.transformation._transform(projectedPoint, scale);
899
901
  },
900
902
 
901
- pointToLatLng: function (/*Point*/ point, /*Number*/ scale, /*(optional) Boolean*/ unbounded)/*-> LatLng*/ {
902
- var untransformedPoint = this.transformation.untransform(point, scale);
903
+ pointToLatLng: function (point, zoom, unbounded) { // (Point, Number[, Boolean]) -> LatLng
904
+ var scale = this.scale(zoom),
905
+ untransformedPoint = this.transformation.untransform(point, scale);
906
+
903
907
  return this.projection.unproject(untransformedPoint, unbounded);
904
908
  //TODO get rid of 'unbounded' everywhere
905
909
  },
906
910
 
907
911
  project: function (latlng) {
908
912
  return this.projection.project(latlng);
913
+ },
914
+
915
+ scale: function (zoom) {
916
+ return 256 * Math.pow(2, zoom);
909
917
  }
910
918
  };
911
919
 
@@ -917,7 +925,7 @@ L.CRS.EPSG3857 = L.Util.extend({}, L.CRS, {
917
925
  projection: L.Projection.SphericalMercator,
918
926
  transformation: new L.Transformation(0.5 / Math.PI, 0.5, -0.5 / Math.PI, 0.5),
919
927
 
920
- project: function (/*LatLng*/ latlng)/*-> Point*/ {
928
+ project: function (latlng) { // (LatLng) -> Point
921
929
  var projectedPoint = this.projection.project(latlng),
922
930
  earthRadius = 6378137;
923
931
  return projectedPoint.multiplyBy(earthRadius);
@@ -946,79 +954,32 @@ L.Map = L.Class.extend({
946
954
  includes: L.Mixin.Events,
947
955
 
948
956
  options: {
949
- // projection
950
- crs: L.CRS.EPSG3857 || L.CRS.EPSG4326,
951
- scale: function (zoom) {
952
- return 256 * Math.pow(2, zoom);
953
- },
954
-
955
- // state
956
- center: null,
957
- zoom: null,
958
- layers: [],
959
-
960
- // interaction
961
- dragging: true,
962
- touchZoom: L.Browser.touch && !L.Browser.android,
963
- scrollWheelZoom: !L.Browser.touch,
964
- doubleClickZoom: true,
965
- boxZoom: true,
966
-
967
- inertia: !L.Browser.android,
968
- inertiaDeceleration: L.Browser.touch ? 3000 : 2000, // px/s^2
969
- inertiaMaxSpeed: L.Browser.touch ? 1500 : 1000, // px/s
970
- inertiaThreshold: L.Browser.touch ? 32 : 16, // ms
957
+ crs: L.CRS.EPSG3857,
971
958
 
972
- // controls
973
- zoomControl: true,
974
- attributionControl: true,
959
+ /*
960
+ center: LatLng,
961
+ zoom: Number,
962
+ layers: Array,
963
+ */
975
964
 
976
- // animation
977
965
  fadeAnimation: L.DomUtil.TRANSITION && !L.Browser.android,
978
- zoomAnimation: L.DomUtil.TRANSITION && !L.Browser.android && !L.Browser.mobileOpera,
979
-
980
- // misc
981
- trackResize: true,
982
- closePopupOnClick: true,
983
- worldCopyJump: true
966
+ trackResize: true
984
967
  },
985
968
 
986
-
987
969
  initialize: function (id, options) { // (HTMLElement or String, Object)
988
- L.Util.setOptions(this, options);
989
-
990
- // TODO method is too big, refactor
991
-
992
- var container = this._container = L.DomUtil.get(id);
993
-
994
- if (container._leaflet) {
995
- throw new Error("Map container is already initialized.");
996
- }
997
- container._leaflet = true;
970
+ options = L.Util.setOptions(this, options);
998
971
 
972
+ this._initContainer(id);
999
973
  this._initLayout();
1000
-
1001
- if (L.DomEvent) {
1002
- this._initEvents();
1003
- if (L.Handler) {
1004
- this._initInteraction();
1005
- }
1006
- if (L.Control) {
1007
- this._initControls();
1008
- }
1009
- }
1010
-
1011
- options = this.options;
974
+ this._initHooks();
975
+ this._initEvents();
1012
976
 
1013
977
  if (options.maxBounds) {
1014
978
  this.setMaxBounds(options.maxBounds);
1015
979
  }
1016
980
 
1017
- var center = options.center,
1018
- zoom = options.zoom;
1019
-
1020
- if (center && typeof zoom !== 'undefined') {
1021
- this.setView(center, zoom, true);
981
+ if (options.center && typeof options.zoom !== 'undefined') {
982
+ this.setView(options.center, options.zoom, true);
1022
983
  }
1023
984
 
1024
985
  this._initLayers(options.layers);
@@ -1029,7 +990,6 @@ L.Map = L.Class.extend({
1029
990
 
1030
991
  // replaced by animation-powered implementation in Map.PanAnimation.js
1031
992
  setView: function (center, zoom) {
1032
- // reset the map view
1033
993
  this._resetView(center, this._limitZoom(zoom));
1034
994
  return this;
1035
995
  },
@@ -1125,9 +1085,7 @@ L.Map = L.Class.extend({
1125
1085
 
1126
1086
  var id = L.Util.stamp(layer);
1127
1087
 
1128
- if (this._layers[id]) {
1129
- return this;
1130
- }
1088
+ if (this._layers[id]) { return this; }
1131
1089
 
1132
1090
  this._layers[id] = layer;
1133
1091
 
@@ -1145,10 +1103,6 @@ L.Map = L.Class.extend({
1145
1103
  layer.on('load', this._onTileLayerLoad, this);
1146
1104
  }
1147
1105
 
1148
- if (this.attributionControl && layer.getAttribution) {
1149
- this.attributionControl.addAttribution(layer.getAttribution());
1150
- }
1151
-
1152
1106
  var onMapLoad = function () {
1153
1107
  layer.onAdd(this, insertAtTheBottom);
1154
1108
  this.fire('layeradd', {layer: layer});
@@ -1178,10 +1132,6 @@ L.Map = L.Class.extend({
1178
1132
  layer.off('load', this._onTileLayerLoad, this);
1179
1133
  }
1180
1134
 
1181
- if (this.attributionControl && layer.getAttribution) {
1182
- this.attributionControl.removeAttribution(layer.getAttribution());
1183
- }
1184
-
1185
1135
  return this.fire('layerremove', {layer: layer});
1186
1136
  },
1187
1137
 
@@ -1206,16 +1156,13 @@ L.Map = L.Class.extend({
1206
1156
 
1207
1157
  this.fire('move');
1208
1158
 
1209
- function fireMoveEnd() {
1210
- this.fire('moveend');
1211
- }
1212
-
1213
1159
  clearTimeout(this._sizeTimer);
1214
- this._sizeTimer = setTimeout(L.Util.bind(fireMoveEnd, this), 200);
1160
+ this._sizeTimer = setTimeout(L.Util.bind(this.fire, this, 'moveend'), 200);
1215
1161
 
1216
1162
  return this;
1217
1163
  },
1218
1164
 
1165
+ // TODO handler.addTo
1219
1166
  addHandler: function (name, HandlerClass) {
1220
1167
  if (!HandlerClass) { return; }
1221
1168
 
@@ -1231,7 +1178,7 @@ L.Map = L.Class.extend({
1231
1178
 
1232
1179
  // public methods for getting map state
1233
1180
 
1234
- getCenter: function (unbounded) { // (Boolean)
1181
+ getCenter: function (unbounded) { // (Boolean) -> LatLng
1235
1182
  var viewHalf = this.getSize().divideBy(2),
1236
1183
  centerPoint = this._getTopLeftPoint().add(viewHalf);
1237
1184
 
@@ -1323,6 +1270,10 @@ L.Map = L.Class.extend({
1323
1270
  getPanes: function () {
1324
1271
  return this._panes;
1325
1272
  },
1273
+
1274
+ getContainer: function () {
1275
+ return this._container;
1276
+ },
1326
1277
 
1327
1278
 
1328
1279
  // conversion methods
@@ -1365,18 +1316,28 @@ L.Map = L.Class.extend({
1365
1316
 
1366
1317
  project: function (latlng, zoom) { // (LatLng[, Number]) -> Point
1367
1318
  zoom = typeof zoom === 'undefined' ? this._zoom : zoom;
1368
- return this.options.crs.latLngToPoint(latlng, this.options.scale(zoom));
1319
+ return this.options.crs.latLngToPoint(latlng, zoom);
1369
1320
  },
1370
1321
 
1371
1322
  unproject: function (point, zoom, unbounded) { // (Point[, Number, Boolean]) -> LatLng
1372
1323
  // TODO remove unbounded, making it true all the time?
1373
1324
  zoom = typeof zoom === 'undefined' ? this._zoom : zoom;
1374
- return this.options.crs.pointToLatLng(point, this.options.scale(zoom), unbounded);
1325
+ return this.options.crs.pointToLatLng(point, zoom, unbounded);
1375
1326
  },
1376
1327
 
1377
1328
 
1378
1329
  // private methods that modify map state
1379
1330
 
1331
+ _initContainer: function (id) {
1332
+ var container = this._container = L.DomUtil.get(id);
1333
+
1334
+ if (container._leaflet) {
1335
+ throw new Error("Map container is already initialized.");
1336
+ }
1337
+
1338
+ container._leaflet = true;
1339
+ },
1340
+
1380
1341
  _initLayout: function () {
1381
1342
  var container = this._container;
1382
1343
 
@@ -1422,6 +1383,15 @@ L.Map = L.Class.extend({
1422
1383
  return L.DomUtil.create('div', className, container || this._objectsPane);
1423
1384
  },
1424
1385
 
1386
+ _initializers: [],
1387
+
1388
+ _initHooks: function () {
1389
+ var i, len;
1390
+ for (i = 0, len = this._initializers.length; i < len; i++) {
1391
+ this._initializers[i].call(this);
1392
+ }
1393
+ },
1394
+
1425
1395
  _resetView: function (center, zoom, preserveMapOffset, afterZoomAnim) {
1426
1396
 
1427
1397
  var zoomChanged = (this._zoom !== zoom);
@@ -1463,7 +1433,7 @@ L.Map = L.Class.extend({
1463
1433
  },
1464
1434
 
1465
1435
  _initLayers: function (layers) {
1466
- layers = layers instanceof Array ? layers : [layers];
1436
+ layers = layers ? (layers instanceof Array ? layers : [layers]) : [];
1467
1437
 
1468
1438
  this._layers = {};
1469
1439
  this._tileLayersNum = 0;
@@ -1475,18 +1445,6 @@ L.Map = L.Class.extend({
1475
1445
  }
1476
1446
  },
1477
1447
 
1478
- _initControls: function () {
1479
- // TODO refactor, this should happen automatically
1480
- if (this.options.zoomControl) {
1481
- this.zoomControl = new L.Control.Zoom();
1482
- this.addControl(this.zoomControl);
1483
- }
1484
- if (this.options.attributionControl) {
1485
- this.attributionControl = new L.Control.Attribution();
1486
- this.addControl(this.attributionControl);
1487
- }
1488
- },
1489
-
1490
1448
  _rawPanBy: function (offset) {
1491
1449
  var newPos = L.DomUtil.getPosition(this._mapPane).subtract(offset);
1492
1450
  L.DomUtil.setPosition(this._mapPane, newPos);
@@ -1496,6 +1454,8 @@ L.Map = L.Class.extend({
1496
1454
  // map events
1497
1455
 
1498
1456
  _initEvents: function () {
1457
+ if (!L.DomEvent) { return; }
1458
+
1499
1459
  L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this);
1500
1460
 
1501
1461
  var events = ['dblclick', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'contextmenu'];
@@ -1547,15 +1507,6 @@ L.Map = L.Class.extend({
1547
1507
  });
1548
1508
  },
1549
1509
 
1550
- _initInteraction: function () {
1551
- this
1552
- .addHandler('dragging', L.Map.Drag)
1553
- .addHandler('touchZoom', L.Map.TouchZoom)
1554
- .addHandler('doubleClickZoom', L.Map.DoubleClickZoom)
1555
- .addHandler('scrollWheelZoom', L.Map.ScrollWheelZoom)
1556
- .addHandler('boxZoom', L.Map.BoxZoom);
1557
- },
1558
-
1559
1510
  _onTileLayerLoad: function () {
1560
1511
  // TODO super-ugly, refactor!!!
1561
1512
  // clear scaled tiles after all new tiles are loaded (for performance)
@@ -1592,6 +1543,15 @@ L.Map = L.Class.extend({
1592
1543
  }
1593
1544
  });
1594
1545
 
1546
+ L.Map.addInitHook = function (fn) {
1547
+ var args = Array.prototype.slice.call(arguments, 1);
1548
+
1549
+ var init = typeof fn === 'function' ? fn : function () {
1550
+ this[fn].apply(this, args);
1551
+ };
1552
+
1553
+ this.prototype._initializers.push(init);
1554
+ };
1595
1555
 
1596
1556
 
1597
1557
  L.Projection.Mercator = {
@@ -1600,7 +1560,7 @@ L.Projection.Mercator = {
1600
1560
  R_MINOR: 6356752.3142,
1601
1561
  R_MAJOR: 6378137,
1602
1562
 
1603
- project: function (/*LatLng*/ latlng) /*-> Point*/ {
1563
+ project: function (latlng) { // (LatLng) -> Point
1604
1564
  var d = L.LatLng.DEG_TO_RAD,
1605
1565
  max = this.MAX_LATITUDE,
1606
1566
  lat = Math.max(Math.min(max, latlng.lat), -max),
@@ -1620,7 +1580,7 @@ L.Projection.Mercator = {
1620
1580
  return new L.Point(x, y);
1621
1581
  },
1622
1582
 
1623
- unproject: function (/*Point*/ point, /*Boolean*/ unbounded) /*-> LatLng*/ {
1583
+ unproject: function (point, unbounded) { // (Point, Boolean) -> LatLng
1624
1584
  var d = L.LatLng.RAD_TO_DEG,
1625
1585
  r = this.R_MAJOR,
1626
1586
  r2 = this.R_MINOR,
@@ -1651,6 +1611,7 @@ L.CRS.EPSG3395 = L.Util.extend({}, L.CRS, {
1651
1611
  code: 'EPSG:3395',
1652
1612
 
1653
1613
  projection: L.Projection.Mercator,
1614
+
1654
1615
  transformation: (function () {
1655
1616
  var m = L.Projection.Mercator,
1656
1617
  r = m.R_MAJOR,
@@ -1681,6 +1642,7 @@ L.TileLayer = L.Class.extend({
1681
1642
  noWrap: false,
1682
1643
  zoomOffset: 0,
1683
1644
  zoomReverse: false,
1645
+ detectRetina: false,
1684
1646
 
1685
1647
  unloadInvisibleTiles: L.Browser.mobile,
1686
1648
  updateWhenIdle: L.Browser.mobile,
@@ -1688,7 +1650,19 @@ L.TileLayer = L.Class.extend({
1688
1650
  },
1689
1651
 
1690
1652
  initialize: function (url, options) {
1691
- L.Util.setOptions(this, options);
1653
+ options = L.Util.setOptions(this, options);
1654
+
1655
+ // detecting retina displays, adjusting tileSize and zoom levels
1656
+ if (options.detectRetina && window.devicePixelRatio > 1 && options.maxZoom > 0) {
1657
+
1658
+ options.tileSize = Math.floor(options.tileSize / 2);
1659
+ options.zoomOffset++;
1660
+
1661
+ if (options.minZoom > 0) {
1662
+ options.minZoom--;
1663
+ }
1664
+ this.options.maxZoom--;
1665
+ }
1692
1666
 
1693
1667
  this._url = url;
1694
1668
 
@@ -2232,12 +2206,17 @@ L.Icon = L.Class.extend({
2232
2206
  },
2233
2207
 
2234
2208
  createShadow: function () {
2235
- return this.options.shadowUrl ? this._createIcon('shadow') : null;
2209
+ return this._createIcon('shadow');
2236
2210
  },
2237
2211
 
2238
2212
  _createIcon: function (name) {
2239
- var img = this._createImg(this.options[name + 'Url']);
2213
+ var src = this._getIconUrl(name);
2214
+
2215
+ if (!src) { return null; }
2216
+
2217
+ var img = this._createImg(src);
2240
2218
  this._setIconStyles(img, name);
2219
+
2241
2220
  return img;
2242
2221
  },
2243
2222
 
@@ -2269,6 +2248,7 @@ L.Icon = L.Class.extend({
2269
2248
 
2270
2249
  _createImg: function (src) {
2271
2250
  var el;
2251
+
2272
2252
  if (!L.Browser.ie6) {
2273
2253
  el = document.createElement('img');
2274
2254
  el.src = src;
@@ -2277,21 +2257,50 @@ L.Icon = L.Class.extend({
2277
2257
  el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")';
2278
2258
  }
2279
2259
  return el;
2260
+ },
2261
+
2262
+ _getIconUrl: function (name) {
2263
+ return this.options[name + 'Url'];
2280
2264
  }
2281
2265
  });
2282
2266
 
2267
+
2268
+ // TODO move to a separate file
2269
+
2283
2270
  L.Icon.Default = L.Icon.extend({
2284
2271
  options: {
2285
- iconUrl: L.ROOT_URL + 'images/marker.png',
2286
2272
  iconSize: new L.Point(25, 41),
2287
2273
  iconAnchor: new L.Point(13, 41),
2288
2274
  popupAnchor: new L.Point(0, -33),
2289
2275
 
2290
- shadowUrl: L.ROOT_URL + 'images/marker-shadow.png',
2291
2276
  shadowSize: new L.Point(41, 41)
2277
+ },
2278
+
2279
+ _getIconUrl: function (name) {
2280
+ var path = L.Icon.Default.imagePath;
2281
+ if (!path) {
2282
+ throw new Error("Couldn't autodetect L.Icon.Default.imagePath, set it manually.");
2283
+ }
2284
+
2285
+ return path + '/marker-' + name + '.png';
2292
2286
  }
2293
2287
  });
2294
2288
 
2289
+ L.Icon.Default.imagePath = (function () {
2290
+ var scripts = document.getElementsByTagName('script'),
2291
+ leafletRe = /\/?leaflet[\-\._]?([\w\-\._]*)\.js\??/;
2292
+
2293
+ var i, len, src, matches;
2294
+
2295
+ for (i = 0, len = scripts.length; i < len; i++) {
2296
+ src = scripts[i].src;
2297
+ matches = src.match(leafletRe);
2298
+
2299
+ if (matches) {
2300
+ return src.split(leafletRe)[0] + '/images';
2301
+ }
2302
+ }
2303
+ }());
2295
2304
 
2296
2305
  /*
2297
2306
  * L.Marker is used to display clickable/draggable icons on the map.
@@ -2503,6 +2512,10 @@ L.DivIcon = L.Icon.extend({
2503
2512
 
2504
2513
 
2505
2514
 
2515
+ L.Map.mergeOptions({
2516
+ closePopupOnClick: true
2517
+ });
2518
+
2506
2519
  L.Popup = L.Class.extend({
2507
2520
  includes: L.Mixin.Events,
2508
2521
 
@@ -2571,9 +2584,14 @@ L.Popup = L.Class.extend({
2571
2584
  },
2572
2585
 
2573
2586
  _close: function () {
2574
- if (this._map) {
2575
- this._map._popup = null;
2576
- this._map.removeLayer(this);
2587
+ var map = this._map;
2588
+
2589
+ if (map) {
2590
+ map._popup = null;
2591
+
2592
+ map
2593
+ .removeLayer(this)
2594
+ .fire('popupclose', {popup: this});
2577
2595
  }
2578
2596
  },
2579
2597
 
@@ -2622,6 +2640,7 @@ L.Popup = L.Class.extend({
2622
2640
  this._contentNode.innerHTML = '';
2623
2641
  this._contentNode.appendChild(this._content);
2624
2642
  }
2643
+ this.fire('contentupdate');
2625
2644
  },
2626
2645
 
2627
2646
  _updateLayout: function () {
@@ -2768,17 +2787,12 @@ L.Map.include({
2768
2787
 
2769
2788
  closePopup: function () {
2770
2789
  if (this._popup) {
2771
- this
2772
- .removeLayer(this._popup)
2773
- .fire('popupclose', {popup: this._popup});
2774
-
2775
- this._popup = null;
2790
+ this._popup._close();
2776
2791
  }
2777
2792
  return this;
2778
2793
  }
2779
2794
  });
2780
2795
 
2781
-
2782
2796
  /*
2783
2797
  * L.LayerGroup is a class to combine several layers so you can manipulate the group (e.g. add/remove it) as one layer.
2784
2798
  */
@@ -2888,6 +2902,14 @@ L.FeatureGroup = L.LayerGroup.extend({
2888
2902
  return this.invoke('setStyle', style);
2889
2903
  },
2890
2904
 
2905
+ getBounds: function () {
2906
+ var bounds = new L.LatLngBounds();
2907
+ this._iterateLayers(function (layer) {
2908
+ bounds.extend(layer instanceof L.Marker ? layer.getLatLng() : layer.getBounds());
2909
+ }, this);
2910
+ return bounds;
2911
+ },
2912
+
2891
2913
  _initEvents: function (layer) {
2892
2914
  var events = ['click', 'dblclick', 'mouseover', 'mouseout'],
2893
2915
  i, len;
@@ -3066,7 +3088,7 @@ L.Path = L.Path.extend({
3066
3088
  // TODO remove duplication with L.Map
3067
3089
  _initEvents: function () {
3068
3090
  if (this.options.clickable) {
3069
- if (!L.Browser.vml) {
3091
+ if (L.Browser.svg || !L.Browser.vml) {
3070
3092
  this._path.setAttribute('class', 'leaflet-clickable');
3071
3093
  }
3072
3094
 
@@ -3728,7 +3750,7 @@ L.Polyline = L.Path.extend({
3728
3750
  onAdd: function (map) {
3729
3751
  L.Path.prototype.onAdd.call(this, map);
3730
3752
 
3731
- if (this.editing.enabled()) {
3753
+ if (this.editing && this.editing.enabled()) {
3732
3754
  this.editing.addHooks();
3733
3755
  }
3734
3756
  },
@@ -3742,7 +3764,7 @@ L.Polyline = L.Path.extend({
3742
3764
  },
3743
3765
 
3744
3766
  _initEvents: function () {
3745
- L.Polyline.superclass._initEvents.call(this);
3767
+ L.Path.prototype._initEvents.call(this);
3746
3768
  },
3747
3769
 
3748
3770
  _getPathPartStr: function (points) {
@@ -4032,7 +4054,7 @@ L.Circle = L.Path.extend({
4032
4054
  point2 = this._map.latLngToLayerPoint(latlng2);
4033
4055
 
4034
4056
  this._point = this._map.latLngToLayerPoint(this._latlng);
4035
- this._radius = Math.round(this._point.x - point2.x);
4057
+ this._radius = Math.max(Math.round(this._point.x - point2.x), 1);
4036
4058
  },
4037
4059
 
4038
4060
  getBounds: function () {
@@ -4047,6 +4069,10 @@ L.Circle = L.Path.extend({
4047
4069
 
4048
4070
  return new L.LatLngBounds(sw, ne);
4049
4071
  },
4072
+
4073
+ getLatLng: function () {
4074
+ return this._latlng;
4075
+ },
4050
4076
 
4051
4077
  getPathString: function () {
4052
4078
  var p = this._point,
@@ -4066,6 +4092,10 @@ L.Circle = L.Path.extend({
4066
4092
  return "AL " + p.x + "," + p.y + " " + r + "," + r + " 0," + (65535 * 360);
4067
4093
  }
4068
4094
  },
4095
+
4096
+ getRadius: function () {
4097
+ return this._mRadius;
4098
+ },
4069
4099
 
4070
4100
  _getLngRadius: function () {
4071
4101
  var equatorLength = 40075017,
@@ -4075,6 +4105,9 @@ L.Circle = L.Path.extend({
4075
4105
  },
4076
4106
 
4077
4107
  _checkIfEmpty: function () {
4108
+ if (!this._map) {
4109
+ return false;
4110
+ }
4078
4111
  var vp = this._map._pathViewport,
4079
4112
  r = this._radius,
4080
4113
  p = this._point;
@@ -4660,6 +4693,19 @@ L.Handler = L.Class.extend({
4660
4693
  * L.Handler.MapDrag is used internally by L.Map to make the map draggable.
4661
4694
  */
4662
4695
 
4696
+ L.Map.mergeOptions({
4697
+ dragging: true,
4698
+
4699
+ inertia: !L.Browser.android,
4700
+ inertiaDeceleration: L.Browser.touch ? 3000 : 2000, // px/s^2
4701
+ inertiaMaxSpeed: L.Browser.touch ? 1500 : 1000, // px/s
4702
+ inertiaThreshold: L.Browser.touch ? 32 : 16, // ms
4703
+
4704
+ // TODO refactor, move to CRS
4705
+ worldCopyJump: true,
4706
+ continuousWorld: false
4707
+ });
4708
+
4663
4709
  L.Map.Drag = L.Handler.extend({
4664
4710
  addHooks: function () {
4665
4711
  if (!this._draggable) {
@@ -4733,7 +4779,7 @@ L.Map.Drag = L.Handler.extend({
4733
4779
 
4734
4780
  _onPreDrag: function () {
4735
4781
  var map = this._map,
4736
- worldWidth = map.options.scale(map.getZoom()),
4782
+ worldWidth = map.options.crs.scale(map.getZoom()),
4737
4783
  halfWidth = Math.round(worldWidth / 2),
4738
4784
  dx = this._initialWorldOffset.x,
4739
4785
  x = this._draggable._newPos.x,
@@ -4748,7 +4794,7 @@ L.Map.Drag = L.Handler.extend({
4748
4794
  var map = this._map,
4749
4795
  options = map.options,
4750
4796
  delay = +new Date() - this._lastTime,
4751
-
4797
+
4752
4798
  noInertia = !options.inertia ||
4753
4799
  delay > options.inertiaThreshold ||
4754
4800
  typeof this._positions[0] === 'undefined';
@@ -4793,11 +4839,16 @@ L.Map.Drag = L.Handler.extend({
4793
4839
  }
4794
4840
  });
4795
4841
 
4842
+ L.Map.addInitHook('addHandler', 'dragging', L.Map.Drag);
4796
4843
 
4797
4844
  /*
4798
4845
  * L.Handler.DoubleClickZoom is used internally by L.Map to add double-click zooming.
4799
4846
  */
4800
4847
 
4848
+ L.Map.mergeOptions({
4849
+ doubleClickZoom: true
4850
+ });
4851
+
4801
4852
  L.Map.DoubleClickZoom = L.Handler.extend({
4802
4853
  addHooks: function () {
4803
4854
  this._map.on('dblclick', this._onDoubleClick);
@@ -4812,11 +4863,16 @@ L.Map.DoubleClickZoom = L.Handler.extend({
4812
4863
  }
4813
4864
  });
4814
4865
 
4866
+ L.Map.addInitHook('addHandler', 'doubleClickZoom', L.Map.DoubleClickZoom);
4815
4867
 
4816
4868
  /*
4817
4869
  * L.Handler.ScrollWheelZoom is used internally by L.Map to enable mouse scroll wheel zooming on the map.
4818
4870
  */
4819
4871
 
4872
+ L.Map.mergeOptions({
4873
+ scrollWheelZoom: !L.Browser.touch
4874
+ });
4875
+
4820
4876
  L.Map.ScrollWheelZoom = L.Handler.extend({
4821
4877
  addHooks: function () {
4822
4878
  L.DomEvent.addListener(this._map._container, 'mousewheel', this._onWheelScroll, this);
@@ -4868,6 +4924,7 @@ L.Map.ScrollWheelZoom = L.Handler.extend({
4868
4924
  }
4869
4925
  });
4870
4926
 
4927
+ L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom);
4871
4928
 
4872
4929
  L.Util.extend(L.DomEvent, {
4873
4930
  // inspired by Zepto touch code by Thomas Fuchs
@@ -4918,6 +4975,10 @@ L.Util.extend(L.DomEvent, {
4918
4975
  * L.Handler.TouchZoom is used internally by L.Map to add touch-zooming on Webkit-powered mobile browsers.
4919
4976
  */
4920
4977
 
4978
+ L.Map.mergeOptions({
4979
+ touchZoom: L.Browser.touch && !L.Browser.android
4980
+ });
4981
+
4921
4982
  L.Map.TouchZoom = L.Handler.extend({
4922
4983
  addHooks: function () {
4923
4984
  L.DomEvent.addListener(this._map._container, 'touchstart', this._onTouchStart, this);
@@ -5008,11 +5069,16 @@ L.Map.TouchZoom = L.Handler.extend({
5008
5069
  }
5009
5070
  });
5010
5071
 
5072
+ L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);
5011
5073
 
5012
5074
  /*
5013
5075
  * L.Handler.ShiftDragZoom is used internally by L.Map to add shift-drag zoom (zoom to a selected bounding box).
5014
5076
  */
5015
5077
 
5078
+ L.Map.mergeOptions({
5079
+ boxZoom: true
5080
+ });
5081
+
5016
5082
  L.Map.BoxZoom = L.Handler.extend({
5017
5083
  initialize: function (map) {
5018
5084
  this._map = map;
@@ -5045,6 +5111,8 @@ L.Map.BoxZoom = L.Handler.extend({
5045
5111
  .addListener(document, 'mousemove', this._onMouseMove, this)
5046
5112
  .addListener(document, 'mouseup', this._onMouseUp, this)
5047
5113
  .preventDefault(e);
5114
+
5115
+ this._map.fire("boxzoomstart");
5048
5116
  },
5049
5117
 
5050
5118
  _onMouseMove: function (e) {
@@ -5083,9 +5151,15 @@ L.Map.BoxZoom = L.Handler.extend({
5083
5151
  map.layerPointToLatLng(layerPoint));
5084
5152
 
5085
5153
  map.fitBounds(bounds);
5154
+
5155
+ map.fire("boxzoomend", {
5156
+ boxZoomBounds: bounds
5157
+ });
5086
5158
  }
5087
5159
  });
5088
5160
 
5161
+ L.Map.addInitHook('addHandler', 'boxZoom', L.Map.BoxZoom);
5162
+
5089
5163
 
5090
5164
  /*
5091
5165
  * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.
@@ -5169,6 +5243,8 @@ L.Handler.PolyEdit = L.Handler.extend({
5169
5243
  removeHooks: function () {
5170
5244
  if (this._poly._map) {
5171
5245
  this._poly._map.removeLayer(this._markerGroup);
5246
+ delete this._markerGroup;
5247
+ delete this._markers;
5172
5248
  }
5173
5249
  },
5174
5250
 
@@ -5245,17 +5321,29 @@ L.Handler.PolyEdit = L.Handler.extend({
5245
5321
  },
5246
5322
 
5247
5323
  _onMarkerClick: function (e) {
5324
+ // Default action on marker click is to remove that marker, but if we remove the marker when latlng count < 3, we don't have a valid polyline anymore
5325
+ if (this._poly._latlngs.length < 3) {
5326
+ return;
5327
+ }
5328
+
5248
5329
  var marker = e.target,
5249
5330
  i = marker._index;
5331
+
5332
+ // Check existence of previous and next markers since they wouldn't exist for edge points on the polyline
5333
+ if (marker._prev && marker._next) {
5334
+ this._createMiddleMarker(marker._prev, marker._next);
5335
+ this._updatePrevNext(marker._prev, marker._next);
5336
+ }
5250
5337
 
5251
- this._createMiddleMarker(marker._prev, marker._next);
5252
- this._updatePrevNext(marker._prev, marker._next);
5253
-
5254
- this._markerGroup
5255
- .removeLayer(marker._middleLeft)
5256
- .removeLayer(marker._middleRight)
5257
- .removeLayer(marker);
5258
-
5338
+ // The marker itself is guaranteed to exist and present in the layer, since we managed to click on it
5339
+ this._markerGroup.removeLayer(marker);
5340
+ // Check for the existence of middle left or middle right
5341
+ if (marker._middleLeft) {
5342
+ this._markerGroup.removeLayer(marker._middleLeft);
5343
+ }
5344
+ if (marker._middleRight) {
5345
+ this._markerGroup.removeLayer(marker._middleRight);
5346
+ }
5259
5347
  this._poly.spliceLatLngs(i, 1);
5260
5348
  this._updateIndexes(i, -1);
5261
5349
  this._poly.fire('edit');
@@ -5271,13 +5359,16 @@ L.Handler.PolyEdit = L.Handler.extend({
5271
5359
 
5272
5360
  _createMiddleMarker: function (marker1, marker2) {
5273
5361
  var latlng = this._getMiddleLatLng(marker1, marker2),
5274
- marker = this._createMarker(latlng);
5362
+ marker = this._createMarker(latlng),
5363
+ onClick,
5364
+ onDragStart,
5365
+ onDragEnd;
5275
5366
 
5276
5367
  marker.setOpacity(0.6);
5277
5368
 
5278
5369
  marker1._middleRight = marker2._middleLeft = marker;
5279
5370
 
5280
- function onDragStart() {
5371
+ onDragStart = function () {
5281
5372
  var i = marker2._index;
5282
5373
 
5283
5374
  marker._index = i;
@@ -5295,21 +5386,21 @@ L.Handler.PolyEdit = L.Handler.extend({
5295
5386
  marker2._index++;
5296
5387
  this._updatePrevNext(marker1, marker);
5297
5388
  this._updatePrevNext(marker, marker2);
5298
- }
5389
+ };
5299
5390
 
5300
- function onDragEnd() {
5391
+ onDragEnd = function () {
5301
5392
  marker.off('dragstart', onDragStart, this);
5302
5393
  marker.off('dragend', onDragEnd, this);
5303
5394
 
5304
5395
  this._createMiddleMarker(marker1, marker);
5305
5396
  this._createMiddleMarker(marker, marker2);
5306
- }
5397
+ };
5307
5398
 
5308
- function onClick() {
5399
+ onClick = function () {
5309
5400
  onDragStart.call(this);
5310
5401
  onDragEnd.call(this);
5311
5402
  this._poly.fire('edit');
5312
- }
5403
+ };
5313
5404
 
5314
5405
  marker
5315
5406
  .on('click', onClick, this)
@@ -5349,26 +5440,25 @@ L.Control = L.Class.extend({
5349
5440
  },
5350
5441
 
5351
5442
  setPosition: function (position) {
5352
- this.options.position = position;
5443
+ var map = this._map;
5353
5444
 
5354
- if (this._map) {
5355
- this._map.removeControl(this);
5356
- this._map.addControl(this);
5445
+ if (map) {
5446
+ map.removeControl(this);
5357
5447
  }
5358
- }
5359
- });
5360
-
5361
5448
 
5449
+ this.options.position = position;
5362
5450
 
5363
- L.Map.include({
5364
- addControl: function (control) {
5365
- var container = control.onAdd(this);
5451
+ if (map) {
5452
+ map.addControl(this);
5453
+ }
5454
+ },
5366
5455
 
5367
- control._container = container;
5368
- control._map = this;
5456
+ addTo: function (map) {
5457
+ this._map = map;
5369
5458
 
5370
- var pos = control.getPosition(),
5371
- corner = this._controlCorners[pos];
5459
+ var container = this._container = this.onAdd(map),
5460
+ pos = this.getPosition(),
5461
+ corner = map._controlCorners[pos];
5372
5462
 
5373
5463
  L.DomUtil.addClass(container, 'leaflet-control');
5374
5464
 
@@ -5377,35 +5467,55 @@ L.Map.include({
5377
5467
  } else {
5378
5468
  corner.appendChild(container);
5379
5469
  }
5470
+
5380
5471
  return this;
5381
5472
  },
5382
5473
 
5383
- removeControl: function (control) {
5384
- var pos = control.getPosition(),
5385
- corner = this._controlCorners[pos];
5474
+ removeFrom: function (map) {
5475
+ var pos = this.getPosition(),
5476
+ corner = map._controlCorners[pos];
5386
5477
 
5387
- corner.removeChild(control._container);
5388
- control._map = null;
5478
+ corner.removeChild(this._container);
5479
+ this._map = null;
5389
5480
 
5390
- if (control.onRemove) {
5391
- control.onRemove(this);
5481
+ if (this.onRemove) {
5482
+ this.onRemove(map);
5392
5483
  }
5484
+
5485
+ return this;
5486
+ }
5487
+ });
5488
+
5489
+
5490
+
5491
+ L.Map.include({
5492
+ addControl: function (control) {
5493
+ control.addTo(this);
5494
+ return this;
5495
+ },
5496
+
5497
+ removeControl: function (control) {
5498
+ control.removeFrom(this);
5393
5499
  return this;
5394
5500
  },
5395
5501
 
5396
5502
  _initControlPos: function () {
5397
- var top = 'leaflet-top',
5398
- bottom = 'leaflet-bottom',
5399
- left = 'leaflet-left',
5400
- right = 'leaflet-right',
5401
- corner = 'leaflet-corner',
5402
- container = this._container,
5403
- corners = this._controlCorners = {};
5404
-
5405
- corners.topleft = L.DomUtil.create('div', [corner, top, left].join(' '), container);
5406
- corners.topright = L.DomUtil.create('div', [corner, top, right].join(' '), container);
5407
- corners.bottomleft = L.DomUtil.create('div', [corner, bottom, left].join(' '), container);
5408
- corners.bottomright = L.DomUtil.create('div', [corner, bottom, right].join(' '), container);
5503
+ var corners = this._controlCorners = {},
5504
+ l = 'leaflet-',
5505
+ container = this._controlContainer =
5506
+ L.DomUtil.create('div', l + 'control-container', this._container);
5507
+
5508
+ function createCorner(vSide, hSide) {
5509
+ var className = l + vSide + ' ' + l + hSide;
5510
+
5511
+ corners[vSide + hSide] =
5512
+ L.DomUtil.create('div', className, container);
5513
+ }
5514
+
5515
+ createCorner('top', 'left');
5516
+ createCorner('top', 'right');
5517
+ createCorner('bottom', 'left');
5518
+ createCorner('bottom', 'right');
5409
5519
  }
5410
5520
  });
5411
5521
 
@@ -5418,7 +5528,7 @@ L.Control.Zoom = L.Control.extend({
5418
5528
  onAdd: function (map) {
5419
5529
  var className = 'leaflet-control-zoom',
5420
5530
  container = L.DomUtil.create('div', className);
5421
-
5531
+
5422
5532
  this._createButton('Zoom in', className + '-in', container, map.zoomIn, map);
5423
5533
  this._createButton('Zoom out', className + '-out', container, map.zoomOut, map);
5424
5534
 
@@ -5439,6 +5549,16 @@ L.Control.Zoom = L.Control.extend({
5439
5549
  }
5440
5550
  });
5441
5551
 
5552
+ L.Map.mergeOptions({
5553
+ zoomControl: true
5554
+ });
5555
+
5556
+ L.Map.addInitHook(function () {
5557
+ if (this.options.zoomControl) {
5558
+ this.zoomControl = new L.Control.Zoom();
5559
+ this.addControl(this.zoomControl);
5560
+ }
5561
+ });
5442
5562
 
5443
5563
  L.Control.Attribution = L.Control.extend({
5444
5564
  options: {
@@ -5453,16 +5573,25 @@ L.Control.Attribution = L.Control.extend({
5453
5573
  },
5454
5574
 
5455
5575
  onAdd: function (map) {
5456
- this._map = map;
5457
-
5458
5576
  this._container = L.DomUtil.create('div', 'leaflet-control-attribution');
5459
5577
  L.DomEvent.disableClickPropagation(this._container);
5460
5578
 
5579
+ map
5580
+ .on('layeradd', this._onLayerAdd, this)
5581
+ .on('layerremove', this._onLayerRemove, this);
5582
+
5461
5583
  this._update();
5462
5584
 
5463
5585
  return this._container;
5464
5586
  },
5465
5587
 
5588
+ onRemove: function (map) {
5589
+ map
5590
+ .off('layeradd', this._onLayerAdd)
5591
+ .off('layerremove', this._onLayerRemove);
5592
+
5593
+ },
5594
+
5466
5595
  setPrefix: function (prefix) {
5467
5596
  this.options.prefix = prefix;
5468
5597
  this._update();
@@ -5498,7 +5627,7 @@ L.Control.Attribution = L.Control.extend({
5498
5627
  }
5499
5628
 
5500
5629
  var prefixAndAttribs = [];
5501
-
5630
+
5502
5631
  if (this.options.prefix) {
5503
5632
  prefixAndAttribs.push(this.options.prefix);
5504
5633
  }
@@ -5507,9 +5636,30 @@ L.Control.Attribution = L.Control.extend({
5507
5636
  }
5508
5637
 
5509
5638
  this._container.innerHTML = prefixAndAttribs.join(' &mdash; ');
5639
+ },
5640
+
5641
+ _onLayerAdd: function (e) {
5642
+ if (e.layer.getAttribution) {
5643
+ this.addAttribution(e.layer.getAttribution());
5644
+ }
5645
+ },
5646
+
5647
+ _onLayerRemove: function (e) {
5648
+ if (e.layer.getAttribution) {
5649
+ this.removeAttribution(e.layer.getAttribution());
5650
+ }
5510
5651
  }
5511
5652
  });
5512
5653
 
5654
+ L.Map.mergeOptions({
5655
+ attributionControl: true
5656
+ });
5657
+
5658
+ L.Map.addInitHook(function () {
5659
+ if (this.options.attributionControl) {
5660
+ this.attributionControl = (new L.Control.Attribution()).addTo(this);
5661
+ }
5662
+ });
5513
5663
 
5514
5664
  L.Control.Scale = L.Control.extend({
5515
5665
  options: {
@@ -5632,8 +5782,6 @@ L.Control.Layers = L.Control.extend({
5632
5782
  },
5633
5783
 
5634
5784
  onAdd: function (map) {
5635
- this._map = map;
5636
-
5637
5785
  this._initLayout();
5638
5786
  this._update();
5639
5787
 
@@ -5660,43 +5808,39 @@ L.Control.Layers = L.Control.extend({
5660
5808
  },
5661
5809
 
5662
5810
  _initLayout: function () {
5663
- this._container = L.DomUtil.create('div', 'leaflet-control-layers');
5811
+ var className = 'leaflet-control-layers',
5812
+ container = this._container = L.DomUtil.create('div', className);
5664
5813
 
5665
5814
  if (!L.Browser.touch) {
5666
- L.DomEvent.disableClickPropagation(this._container);
5815
+ L.DomEvent.disableClickPropagation(container);
5667
5816
  } else {
5668
- L.DomEvent.addListener(this._container, 'click', L.DomEvent.stopPropagation);
5817
+ L.DomEvent.addListener(container, 'click', L.DomEvent.stopPropagation);
5669
5818
  }
5670
5819
 
5671
- this._form = L.DomUtil.create('form', 'leaflet-control-layers-list');
5820
+ var form = this._form = L.DomUtil.create('form', className + '-list');
5672
5821
 
5673
5822
  if (this.options.collapsed) {
5674
- L.DomEvent.addListener(this._container, 'mouseover', this._expand, this);
5675
- L.DomEvent.addListener(this._container, 'mouseout', this._collapse, this);
5823
+ L.DomEvent
5824
+ .addListener(container, 'mouseover', this._expand, this)
5825
+ .addListener(container, 'mouseout', this._collapse, this);
5676
5826
 
5677
- var link = this._layersLink = L.DomUtil.create('a', 'leaflet-control-layers-toggle');
5827
+ var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
5678
5828
  link.href = '#';
5679
5829
  link.title = 'Layers';
5680
5830
 
5681
- if (L.Browser.touch) {
5682
- L.DomEvent.addListener(link, 'click', this._expand, this);
5683
- //L.DomEvent.disableClickPropagation(link);
5684
- } else {
5685
- L.DomEvent.addListener(link, 'focus', this._expand, this);
5686
- }
5831
+ L.DomEvent.addListener(link, L.Browser.touch ? 'click' : 'focus', this._expand, this);
5832
+
5687
5833
  this._map.on('movestart', this._collapse, this);
5688
5834
  // TODO keyboard accessibility
5689
-
5690
- this._container.appendChild(link);
5691
5835
  } else {
5692
5836
  this._expand();
5693
5837
  }
5694
5838
 
5695
- this._baseLayersList = L.DomUtil.create('div', 'leaflet-control-layers-base', this._form);
5696
- this._separator = L.DomUtil.create('div', 'leaflet-control-layers-separator', this._form);
5697
- this._overlaysList = L.DomUtil.create('div', 'leaflet-control-layers-overlays', this._form);
5839
+ this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
5840
+ this._separator = L.DomUtil.create('div', className + '-separator', form);
5841
+ this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);
5698
5842
 
5699
- this._container.appendChild(this._form);
5843
+ container.appendChild(form);
5700
5844
  },
5701
5845
 
5702
5846
  _addLayer: function (layer, name, overlay) {
@@ -6045,6 +6189,7 @@ L.Transition = L.Transition.NATIVE ? L.Transition : L.Transition.extend({
6045
6189
  });
6046
6190
 
6047
6191
 
6192
+
6048
6193
  L.Map.include(!(L.Transition && L.Transition.implemented()) ? {} : {
6049
6194
  setView: function (center, zoom, forceReset) {
6050
6195
  zoom = this._limitZoom(zoom);
@@ -6125,6 +6270,10 @@ L.Map.include(!(L.Transition && L.Transition.implemented()) ? {} : {
6125
6270
  });
6126
6271
 
6127
6272
 
6273
+ L.Map.mergeOptions({
6274
+ zoomAnimation: L.DomUtil.TRANSITION && !L.Browser.android && !L.Browser.mobileOpera
6275
+ });
6276
+
6128
6277
  L.Map.include(!L.DomUtil.TRANSITION ? {} : {
6129
6278
  _zoomToIfCenterInView: function (center, zoom, centerOffset) {
6130
6279
 
@@ -6359,3 +6508,6 @@ L.Map.include({
6359
6508
  });
6360
6509
 
6361
6510
 
6511
+
6512
+
6513
+ }());