@teipublisher/pb-components 2.10.1 → 2.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/css/gridjs/mermaid.min.css +1 -1
  3. package/css/leaflet/leaflet.css +63 -42
  4. package/css/prismjs/prism-coy.css +4 -3
  5. package/css/prismjs/prism-coy.min.css +1 -0
  6. package/css/prismjs/prism-dark.min.css +1 -0
  7. package/css/prismjs/prism-funky.min.css +1 -0
  8. package/css/prismjs/prism-okaidia.min.css +1 -0
  9. package/css/prismjs/prism-solarizedlight.min.css +1 -0
  10. package/css/prismjs/prism-tomorrow.min.css +1 -0
  11. package/css/prismjs/prism-twilight.css +3 -33
  12. package/css/prismjs/prism-twilight.min.css +1 -0
  13. package/css/prismjs/prism.min.css +1 -0
  14. package/css/tom-select/tom-select.bootstrap4.min.css +1 -1
  15. package/css/tom-select/tom-select.bootstrap5.min.css +1 -1
  16. package/css/tom-select/tom-select.default.min.css +1 -1
  17. package/css/tom-select/tom-select.min.css +1 -1
  18. package/dist/{iron-form-9e72ac45.js → iron-form-89b60473.js} +1 -1
  19. package/dist/jinn-codemirror-da585937.js +1 -0
  20. package/dist/{paper-checkbox-102e3b43.js → paper-checkbox-56ead3d4.js} +100 -109
  21. package/dist/pb-code-editor.js +1 -1
  22. package/dist/pb-component-docs.js +94 -103
  23. package/dist/pb-components-bundle.js +171 -162
  24. package/dist/pb-edit-app.js +29 -29
  25. package/dist/{pb-i18n-f7a50012.js → pb-i18n-9000294c.js} +1 -1
  26. package/dist/pb-leaflet-map.js +1 -1
  27. package/dist/pb-odd-editor.js +1 -1
  28. package/dist/pb-tify.js +1 -1
  29. package/dist/{vaadin-element-mixin-b6179444.js → vaadin-element-mixin-67c5648d.js} +17 -18
  30. package/gh-pages.js +6 -0
  31. package/lib/leaflet-src.js +1623 -1173
  32. package/lib/paged.polyfill.js +1335 -1124
  33. package/package.json +4 -3
  34. package/src/pb-page.js +2 -1
  35. package/dist/jinn-codemirror-13c59456.js +0 -1
  36. /package/dist/{es-global-bridge-6abe3a88.js → es-global-bridge-5c039c0b.js} +0 -0
  37. /package/dist/{pb-mixin-ea2e9070.js → pb-mixin-d61c06b6.js} +0 -0
@@ -1,15 +1,15 @@
1
1
  /* @preserve
2
- * Leaflet 1.7.1, a JS library for interactive maps. http://leafletjs.com
3
- * (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade
2
+ * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com
3
+ * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade
4
4
  */
5
5
 
6
6
  (function (global, factory) {
7
7
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
8
8
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
9
- (factory((global.L = {})));
10
- }(this, (function (exports) { 'use strict';
9
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.leaflet = {}));
10
+ })(this, (function (exports) { 'use strict';
11
11
 
12
- var version = "1.7.1";
12
+ var version = "1.9.4";
13
13
 
14
14
  /*
15
15
  * @namespace Util
@@ -33,7 +33,7 @@
33
33
 
34
34
  // @function create(proto: Object, properties?: Object): Object
35
35
  // Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
36
- var create = Object.create || (function () {
36
+ var create$2 = Object.create || (function () {
37
37
  function F() {}
38
38
  return function (proto) {
39
39
  F.prototype = proto;
@@ -65,10 +65,10 @@
65
65
  // @function stamp(obj: Object): Number
66
66
  // Returns the unique ID of an object, assigning it one if it doesn't have it.
67
67
  function stamp(obj) {
68
- /*eslint-disable */
69
- obj._leaflet_id = obj._leaflet_id || ++lastId;
68
+ if (!('_leaflet_id' in obj)) {
69
+ obj['_leaflet_id'] = ++lastId;
70
+ }
70
71
  return obj._leaflet_id;
71
- /* eslint-enable */
72
72
  }
73
73
 
74
74
  // @function throttle(fn: Function, time: Number, context: Object): Function
@@ -121,10 +121,13 @@
121
121
  // Returns a function which always returns `false`.
122
122
  function falseFn() { return false; }
123
123
 
124
- // @function formatNum(num: Number, digits?: Number): Number
125
- // Returns the number `num` rounded to `digits` decimals, or to 6 decimals by default.
126
- function formatNum(num, digits) {
127
- var pow = Math.pow(10, (digits === undefined ? 6 : digits));
124
+ // @function formatNum(num: Number, precision?: Number|false): Number
125
+ // Returns the number `num` rounded with specified `precision`.
126
+ // The default `precision` value is 6 decimal places.
127
+ // `false` can be passed to skip any processing (can be useful to avoid round-off errors).
128
+ function formatNum(num, precision) {
129
+ if (precision === false) { return num; }
130
+ var pow = Math.pow(10, precision === undefined ? 6 : precision);
128
131
  return Math.round(num * pow) / pow;
129
132
  }
130
133
 
@@ -144,7 +147,7 @@
144
147
  // Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.
145
148
  function setOptions(obj, options) {
146
149
  if (!Object.prototype.hasOwnProperty.call(obj, 'options')) {
147
- obj.options = obj.options ? create(obj.options) : {};
150
+ obj.options = obj.options ? create$2(obj.options) : {};
148
151
  }
149
152
  for (var i in options) {
150
153
  obj.options[i] = options[i];
@@ -165,7 +168,7 @@
165
168
  return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
166
169
  }
167
170
 
168
- var templateRe = /\{ *([\w_-]+) *\}/g;
171
+ var templateRe = /\{ *([\w_ -]+) *\}/g;
169
172
 
170
173
  // @function template(str: String, data: Object): String
171
174
  // Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
@@ -207,7 +210,7 @@
207
210
  // mobile devices (by setting image `src` to this string).
208
211
  var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
209
212
 
210
- // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
213
+ // inspired by https://paulirish.com/2011/requestanimationframe-for-smart-animating/
211
214
 
212
215
  function getPrefixed(name) {
213
216
  return window['webkit' + name] || window['moz' + name] || window['ms' + name];
@@ -250,11 +253,12 @@
250
253
  }
251
254
  }
252
255
 
253
- var Util = ({
256
+ var Util = {
257
+ __proto__: null,
254
258
  extend: extend,
255
- create: create,
259
+ create: create$2,
256
260
  bind: bind,
257
- lastId: lastId,
261
+ get lastId () { return lastId; },
258
262
  stamp: stamp,
259
263
  throttle: throttle,
260
264
  wrapNum: wrapNum,
@@ -272,7 +276,7 @@
272
276
  cancelFn: cancelFn,
273
277
  requestAnimFrame: requestAnimFrame,
274
278
  cancelAnimFrame: cancelAnimFrame
275
- });
279
+ };
276
280
 
277
281
  // @class Class
278
282
  // @aka L.Class
@@ -291,6 +295,8 @@
291
295
  // Returns a Javascript function that is a class constructor (to be called with `new`).
292
296
  var NewClass = function () {
293
297
 
298
+ setOptions(this);
299
+
294
300
  // call the constructor
295
301
  if (this.initialize) {
296
302
  this.initialize.apply(this, arguments);
@@ -302,7 +308,7 @@
302
308
 
303
309
  var parentProto = NewClass.__super__ = this.prototype;
304
310
 
305
- var proto = create(parentProto);
311
+ var proto = create$2(parentProto);
306
312
  proto.constructor = NewClass;
307
313
 
308
314
  NewClass.prototype = proto;
@@ -317,24 +323,25 @@
317
323
  // mix static properties into the class
318
324
  if (props.statics) {
319
325
  extend(NewClass, props.statics);
320
- delete props.statics;
321
326
  }
322
327
 
323
328
  // mix includes into the prototype
324
329
  if (props.includes) {
325
330
  checkDeprecatedMixinEvents(props.includes);
326
331
  extend.apply(null, [proto].concat(props.includes));
327
- delete props.includes;
328
332
  }
329
333
 
334
+ // mix given properties into the prototype
335
+ extend(proto, props);
336
+ delete proto.statics;
337
+ delete proto.includes;
338
+
330
339
  // merge options
331
340
  if (proto.options) {
332
- props.options = extend(create(proto.options), props.options);
341
+ proto.options = parentProto.options ? create$2(parentProto.options) : {};
342
+ extend(proto.options, props.options);
333
343
  }
334
344
 
335
- // mix given properties into the prototype
336
- extend(proto, props);
337
-
338
345
  proto._initHooks = [];
339
346
 
340
347
  // add method for calling all hooks
@@ -360,7 +367,12 @@
360
367
  // @function include(properties: Object): this
361
368
  // [Includes a mixin](#class-includes) into the current class.
362
369
  Class.include = function (props) {
370
+ var parentOptions = this.prototype.options;
363
371
  extend(this.prototype, props);
372
+ if (props.options) {
373
+ this.prototype.options = parentOptions;
374
+ this.mergeOptions(props.options);
375
+ }
364
376
  return this;
365
377
  };
366
378
 
@@ -386,6 +398,7 @@
386
398
  };
387
399
 
388
400
  function checkDeprecatedMixinEvents(includes) {
401
+ /* global L: true */
389
402
  if (typeof L === 'undefined' || !L || !L.Mixin) { return; }
390
403
 
391
404
  includes = isArray(includes) ? includes : [includes];
@@ -467,7 +480,7 @@
467
480
  */
468
481
  off: function (types, fn, context) {
469
482
 
470
- if (!types) {
483
+ if (!arguments.length) {
471
484
  // clear all listeners if called without arguments
472
485
  delete this._events;
473
486
 
@@ -479,8 +492,13 @@
479
492
  } else {
480
493
  types = splitWords(types);
481
494
 
495
+ var removeAll = arguments.length === 1;
482
496
  for (var i = 0, len = types.length; i < len; i++) {
483
- this._off(types[i], fn, context);
497
+ if (removeAll) {
498
+ this._off(types[i]);
499
+ } else {
500
+ this._off(types[i], fn, context);
501
+ }
484
502
  }
485
503
  }
486
504
 
@@ -488,31 +506,30 @@
488
506
  },
489
507
 
490
508
  // attach listener (without syntactic sugar now)
491
- _on: function (type, fn, context) {
492
- this._events = this._events || {};
509
+ _on: function (type, fn, context, _once) {
510
+ if (typeof fn !== 'function') {
511
+ console.warn('wrong listener type: ' + typeof fn);
512
+ return;
513
+ }
493
514
 
494
- /* get/init listeners for type */
495
- var typeListeners = this._events[type];
496
- if (!typeListeners) {
497
- typeListeners = [];
498
- this._events[type] = typeListeners;
515
+ // check if fn already there
516
+ if (this._listens(type, fn, context) !== false) {
517
+ return;
499
518
  }
500
519
 
501
520
  if (context === this) {
502
521
  // Less memory footprint.
503
522
  context = undefined;
504
523
  }
505
- var newListener = {fn: fn, ctx: context},
506
- listeners = typeListeners;
507
524
 
508
- // check if fn already there
509
- for (var i = 0, len = listeners.length; i < len; i++) {
510
- if (listeners[i].fn === fn && listeners[i].ctx === context) {
511
- return;
512
- }
525
+ var newListener = {fn: fn, ctx: context};
526
+ if (_once) {
527
+ newListener.once = true;
513
528
  }
514
529
 
515
- listeners.push(newListener);
530
+ this._events = this._events || {};
531
+ this._events[type] = this._events[type] || [];
532
+ this._events[type].push(newListener);
516
533
  },
517
534
 
518
535
  _off: function (type, fn, context) {
@@ -520,53 +537,50 @@
520
537
  i,
521
538
  len;
522
539
 
523
- if (!this._events) { return; }
540
+ if (!this._events) {
541
+ return;
542
+ }
524
543
 
525
544
  listeners = this._events[type];
526
-
527
545
  if (!listeners) {
528
546
  return;
529
547
  }
530
548
 
531
- if (!fn) {
532
- // Set all removed listeners to noop so they are not called if remove happens in fire
533
- for (i = 0, len = listeners.length; i < len; i++) {
534
- listeners[i].fn = falseFn;
549
+ if (arguments.length === 1) { // remove all
550
+ if (this._firingCount) {
551
+ // Set all removed listeners to noop
552
+ // so they are not called if remove happens in fire
553
+ for (i = 0, len = listeners.length; i < len; i++) {
554
+ listeners[i].fn = falseFn;
555
+ }
535
556
  }
536
557
  // clear all listeners for a type if function isn't specified
537
558
  delete this._events[type];
538
559
  return;
539
560
  }
540
561
 
541
- if (context === this) {
542
- context = undefined;
562
+ if (typeof fn !== 'function') {
563
+ console.warn('wrong listener type: ' + typeof fn);
564
+ return;
543
565
  }
544
566
 
545
- if (listeners) {
546
-
547
- // find fn and remove it
548
- for (i = 0, len = listeners.length; i < len; i++) {
549
- var l = listeners[i];
550
- if (l.ctx !== context) { continue; }
551
- if (l.fn === fn) {
552
-
553
- // set the removed listener to noop so that's not called if remove happens in fire
554
- l.fn = falseFn;
567
+ // find fn and remove it
568
+ var index = this._listens(type, fn, context);
569
+ if (index !== false) {
570
+ var listener = listeners[index];
571
+ if (this._firingCount) {
572
+ // set the removed listener to noop so that's not called if remove happens in fire
573
+ listener.fn = falseFn;
555
574
 
556
- if (this._firingCount) {
557
- /* copy array in case events are being fired */
558
- this._events[type] = listeners = listeners.slice();
559
- }
560
- listeners.splice(i, 1);
561
-
562
- return;
563
- }
575
+ /* copy array in case events are being fired */
576
+ this._events[type] = listeners = listeners.slice();
564
577
  }
578
+ listeners.splice(index, 1);
565
579
  }
566
580
  },
567
581
 
568
582
  // @method fire(type: String, data?: Object, propagate?: Boolean): this
569
- // Fires an event of the specified type. You can optionally provide an data
583
+ // Fires an event of the specified type. You can optionally provide a data
570
584
  // object — the first argument of the listener function will contain its
571
585
  // properties. The event can optionally be propagated to event parents.
572
586
  fire: function (type, data, propagate) {
@@ -580,12 +594,16 @@
580
594
 
581
595
  if (this._events) {
582
596
  var listeners = this._events[type];
583
-
584
597
  if (listeners) {
585
598
  this._firingCount = (this._firingCount + 1) || 1;
586
599
  for (var i = 0, len = listeners.length; i < len; i++) {
587
600
  var l = listeners[i];
588
- l.fn.call(l.ctx || this, event);
601
+ // off overwrites l.fn, so we need to copy fn to a var
602
+ var fn = l.fn;
603
+ if (l.once) {
604
+ this.off(type, fn, l.ctx);
605
+ }
606
+ fn.call(l.ctx || this, event);
589
607
  }
590
608
 
591
609
  this._firingCount--;
@@ -600,42 +618,86 @@
600
618
  return this;
601
619
  },
602
620
 
603
- // @method listens(type: String): Boolean
621
+ // @method listens(type: String, propagate?: Boolean): Boolean
622
+ // @method listens(type: String, fn: Function, context?: Object, propagate?: Boolean): Boolean
604
623
  // Returns `true` if a particular event type has any listeners attached to it.
605
- listens: function (type, propagate) {
624
+ // The verification can optionally be propagated, it will return `true` if parents have the listener attached to it.
625
+ listens: function (type, fn, context, propagate) {
626
+ if (typeof type !== 'string') {
627
+ console.warn('"string" type argument expected');
628
+ }
629
+
630
+ // we don't overwrite the input `fn` value, because we need to use it for propagation
631
+ var _fn = fn;
632
+ if (typeof fn !== 'function') {
633
+ propagate = !!fn;
634
+ _fn = undefined;
635
+ context = undefined;
636
+ }
637
+
606
638
  var listeners = this._events && this._events[type];
607
- if (listeners && listeners.length) { return true; }
639
+ if (listeners && listeners.length) {
640
+ if (this._listens(type, _fn, context) !== false) {
641
+ return true;
642
+ }
643
+ }
608
644
 
609
645
  if (propagate) {
610
646
  // also check parents for listeners if event propagates
611
647
  for (var id in this._eventParents) {
612
- if (this._eventParents[id].listens(type, propagate)) { return true; }
648
+ if (this._eventParents[id].listens(type, fn, context, propagate)) { return true; }
613
649
  }
614
650
  }
615
651
  return false;
616
652
  },
617
653
 
654
+ // returns the index (number) or false
655
+ _listens: function (type, fn, context) {
656
+ if (!this._events) {
657
+ return false;
658
+ }
659
+
660
+ var listeners = this._events[type] || [];
661
+ if (!fn) {
662
+ return !!listeners.length;
663
+ }
664
+
665
+ if (context === this) {
666
+ // Less memory footprint.
667
+ context = undefined;
668
+ }
669
+
670
+ for (var i = 0, len = listeners.length; i < len; i++) {
671
+ if (listeners[i].fn === fn && listeners[i].ctx === context) {
672
+ return i;
673
+ }
674
+ }
675
+ return false;
676
+
677
+ },
678
+
618
679
  // @method once(…): this
619
680
  // Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.
620
681
  once: function (types, fn, context) {
621
682
 
683
+ // types can be a map of types/handlers
622
684
  if (typeof types === 'object') {
623
685
  for (var type in types) {
624
- this.once(type, types[type], fn);
686
+ // we don't process space-separated events here for performance;
687
+ // it's a hot path since Layer uses the on(obj) syntax
688
+ this._on(type, types[type], fn, true);
625
689
  }
626
- return this;
627
- }
628
690
 
629
- var handler = bind(function () {
630
- this
631
- .off(types, fn, context)
632
- .off(types, handler, context);
633
- }, this);
691
+ } else {
692
+ // types can be a string of space-separated words
693
+ types = splitWords(types);
694
+
695
+ for (var i = 0, len = types.length; i < len; i++) {
696
+ this._on(types[i], fn, context, true);
697
+ }
698
+ }
634
699
 
635
- // add a listener that's executed once and removed after that
636
- return this
637
- .on(types, fn, context)
638
- .on(types, handler, context);
700
+ return this;
639
701
  },
640
702
 
641
703
  // @method addEventParent(obj: Evented): this
@@ -951,21 +1013,36 @@
951
1013
  Bounds.prototype = {
952
1014
  // @method extend(point: Point): this
953
1015
  // Extends the bounds to contain the given point.
954
- extend: function (point) { // (Point)
955
- point = toPoint(point);
1016
+
1017
+ // @alternative
1018
+ // @method extend(otherBounds: Bounds): this
1019
+ // Extend the bounds to contain the given bounds
1020
+ extend: function (obj) {
1021
+ var min2, max2;
1022
+ if (!obj) { return this; }
1023
+
1024
+ if (obj instanceof Point || typeof obj[0] === 'number' || 'x' in obj) {
1025
+ min2 = max2 = toPoint(obj);
1026
+ } else {
1027
+ obj = toBounds(obj);
1028
+ min2 = obj.min;
1029
+ max2 = obj.max;
1030
+
1031
+ if (!min2 || !max2) { return this; }
1032
+ }
956
1033
 
957
1034
  // @property min: Point
958
1035
  // The top left corner of the rectangle.
959
1036
  // @property max: Point
960
1037
  // The bottom right corner of the rectangle.
961
1038
  if (!this.min && !this.max) {
962
- this.min = point.clone();
963
- this.max = point.clone();
1039
+ this.min = min2.clone();
1040
+ this.max = max2.clone();
964
1041
  } else {
965
- this.min.x = Math.min(point.x, this.min.x);
966
- this.max.x = Math.max(point.x, this.max.x);
967
- this.min.y = Math.min(point.y, this.min.y);
968
- this.max.y = Math.max(point.y, this.max.y);
1042
+ this.min.x = Math.min(min2.x, this.min.x);
1043
+ this.max.x = Math.max(max2.x, this.max.x);
1044
+ this.min.y = Math.min(min2.y, this.min.y);
1045
+ this.max.y = Math.max(max2.y, this.max.y);
969
1046
  }
970
1047
  return this;
971
1048
  },
@@ -973,7 +1050,7 @@
973
1050
  // @method getCenter(round?: Boolean): Point
974
1051
  // Returns the center point of the bounds.
975
1052
  getCenter: function (round) {
976
- return new Point(
1053
+ return toPoint(
977
1054
  (this.min.x + this.max.x) / 2,
978
1055
  (this.min.y + this.max.y) / 2, round);
979
1056
  },
@@ -981,13 +1058,13 @@
981
1058
  // @method getBottomLeft(): Point
982
1059
  // Returns the bottom-left point of the bounds.
983
1060
  getBottomLeft: function () {
984
- return new Point(this.min.x, this.max.y);
1061
+ return toPoint(this.min.x, this.max.y);
985
1062
  },
986
1063
 
987
1064
  // @method getTopRight(): Point
988
1065
  // Returns the top-right point of the bounds.
989
1066
  getTopRight: function () { // -> Point
990
- return new Point(this.max.x, this.min.y);
1067
+ return toPoint(this.max.x, this.min.y);
991
1068
  },
992
1069
 
993
1070
  // @method getTopLeft(): Point
@@ -1067,9 +1144,40 @@
1067
1144
  return xOverlaps && yOverlaps;
1068
1145
  },
1069
1146
 
1147
+ // @method isValid(): Boolean
1148
+ // Returns `true` if the bounds are properly initialized.
1070
1149
  isValid: function () {
1071
1150
  return !!(this.min && this.max);
1072
- }
1151
+ },
1152
+
1153
+
1154
+ // @method pad(bufferRatio: Number): Bounds
1155
+ // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
1156
+ // For example, a ratio of 0.5 extends the bounds by 50% in each direction.
1157
+ // Negative values will retract the bounds.
1158
+ pad: function (bufferRatio) {
1159
+ var min = this.min,
1160
+ max = this.max,
1161
+ heightBuffer = Math.abs(min.x - max.x) * bufferRatio,
1162
+ widthBuffer = Math.abs(min.y - max.y) * bufferRatio;
1163
+
1164
+
1165
+ return toBounds(
1166
+ toPoint(min.x - heightBuffer, min.y - widthBuffer),
1167
+ toPoint(max.x + heightBuffer, max.y + widthBuffer));
1168
+ },
1169
+
1170
+
1171
+ // @method equals(otherBounds: Bounds): Boolean
1172
+ // Returns `true` if the rectangle is equivalent to the given bounds.
1173
+ equals: function (bounds) {
1174
+ if (!bounds) { return false; }
1175
+
1176
+ bounds = toBounds(bounds);
1177
+
1178
+ return this.min.equals(bounds.getTopLeft()) &&
1179
+ this.max.equals(bounds.getBottomRight());
1180
+ },
1073
1181
  };
1074
1182
 
1075
1183
 
@@ -1475,7 +1583,7 @@
1475
1583
  * Object that defines coordinate reference systems for projecting
1476
1584
  * geographical points into pixel (screen) coordinates and back (and to
1477
1585
  * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See
1478
- * [spatial reference system](http://en.wikipedia.org/wiki/Coordinate_reference_system).
1586
+ * [spatial reference system](https://en.wikipedia.org/wiki/Spatial_reference_system).
1479
1587
  *
1480
1588
  * Leaflet defines the most usual CRSs by default. If you want to use a
1481
1589
  * CRS not defined by default, take a look at the
@@ -1618,7 +1726,7 @@
1618
1726
 
1619
1727
  // Mean Earth Radius, as recommended for use by
1620
1728
  // the International Union of Geodesy and Geophysics,
1621
- // see http://rosettacode.org/wiki/Haversine_formula
1729
+ // see https://rosettacode.org/wiki/Haversine_formula
1622
1730
  R: 6371000,
1623
1731
 
1624
1732
  // distance between two geographical points using spherical law of cosines approximation
@@ -1802,7 +1910,7 @@
1802
1910
  }
1803
1911
 
1804
1912
  // closes the ring for polygons; "x" is VML syntax
1805
- str += closed ? (svg ? 'z' : 'x') : '';
1913
+ str += closed ? (Browser.svg ? 'z' : 'x') : '';
1806
1914
  }
1807
1915
 
1808
1916
  // SVG complains about empty path strings
@@ -1824,7 +1932,7 @@
1824
1932
  * ```
1825
1933
  */
1826
1934
 
1827
- var style$1 = document.documentElement.style;
1935
+ var style = document.documentElement.style;
1828
1936
 
1829
1937
  // @property ie: Boolean; `true` for all Internet Explorer versions (not Edge).
1830
1938
  var ie = 'ActiveXObject' in window;
@@ -1840,15 +1948,15 @@
1840
1948
  var webkit = userAgentContains('webkit');
1841
1949
 
1842
1950
  // @property android: Boolean
1843
- // `true` for any browser running on an Android platform.
1951
+ // **Deprecated.** `true` for any browser running on an Android platform.
1844
1952
  var android = userAgentContains('android');
1845
1953
 
1846
- // @property android23: Boolean; `true` for browsers running on Android 2 or Android 3.
1954
+ // @property android23: Boolean; **Deprecated.** `true` for browsers running on Android 2 or Android 3.
1847
1955
  var android23 = userAgentContains('android 2') || userAgentContains('android 3');
1848
1956
 
1849
1957
  /* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */
1850
1958
  var webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit
1851
- // @property androidStock: Boolean; `true` for the Android stock browser (i.e. not Chrome)
1959
+ // @property androidStock: Boolean; **Deprecated.** `true` for the Android stock browser (i.e. not Chrome)
1852
1960
  var androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window);
1853
1961
 
1854
1962
  // @property opera: Boolean; `true` for the Opera browser
@@ -1867,19 +1975,19 @@
1867
1975
 
1868
1976
  // @property opera12: Boolean
1869
1977
  // `true` for the Opera browser supporting CSS transforms (version 12 or later).
1870
- var opera12 = 'OTransition' in style$1;
1978
+ var opera12 = 'OTransition' in style;
1871
1979
 
1872
1980
  // @property win: Boolean; `true` when the browser is running in a Windows platform
1873
1981
  var win = navigator.platform.indexOf('Win') === 0;
1874
1982
 
1875
1983
  // @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms.
1876
- var ie3d = ie && ('transition' in style$1);
1984
+ var ie3d = ie && ('transition' in style);
1877
1985
 
1878
1986
  // @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms.
1879
1987
  var webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23;
1880
1988
 
1881
1989
  // @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms.
1882
- var gecko3d = 'MozPerspective' in style$1;
1990
+ var gecko3d = 'MozPerspective' in style;
1883
1991
 
1884
1992
  // @property any3d: Boolean
1885
1993
  // `true` for all browsers supporting CSS transforms.
@@ -1903,13 +2011,17 @@
1903
2011
  // `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).
1904
2012
  var pointer = !!(window.PointerEvent || msPointer);
1905
2013
 
1906
- // @property touch: Boolean
2014
+ // @property touchNative: Boolean
1907
2015
  // `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).
1908
- // This does not necessarily mean that the browser is running in a computer with
2016
+ // **This does not necessarily mean** that the browser is running in a computer with
1909
2017
  // a touchscreen, it only means that the browser is capable of understanding
1910
2018
  // touch events.
1911
- var touch = !window.L_NO_TOUCH && (pointer || 'ontouchstart' in window ||
1912
- (window.DocumentTouch && document instanceof window.DocumentTouch));
2019
+ var touchNative = 'ontouchstart' in window || !!window.TouchEvent;
2020
+
2021
+ // @property touch: Boolean
2022
+ // `true` for all browsers supporting either [touch](#browser-touch) or [pointer](#browser-pointer) events.
2023
+ // Note: pointer events will be preferred (if available), and processed for all `touch*` listeners.
2024
+ var touch = !window.L_NO_TOUCH && (touchNative || pointer);
1913
2025
 
1914
2026
  // @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device.
1915
2027
  var mobileOpera = mobile && opera;
@@ -1942,17 +2054,23 @@
1942
2054
 
1943
2055
  // @property canvas: Boolean
1944
2056
  // `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
1945
- var canvas = (function () {
2057
+ var canvas$1 = (function () {
1946
2058
  return !!document.createElement('canvas').getContext;
1947
2059
  }());
1948
2060
 
1949
2061
  // @property svg: Boolean
1950
2062
  // `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).
1951
- var svg = !!(document.createElementNS && svgCreate('svg').createSVGRect);
2063
+ var svg$1 = !!(document.createElementNS && svgCreate('svg').createSVGRect);
2064
+
2065
+ var inlineSvg = !!svg$1 && (function () {
2066
+ var div = document.createElement('div');
2067
+ div.innerHTML = '<svg/>';
2068
+ return (div.firstChild && div.firstChild.namespaceURI) === 'http://www.w3.org/2000/svg';
2069
+ })();
1952
2070
 
1953
2071
  // @property vml: Boolean
1954
2072
  // `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).
1955
- var vml = !svg && (function () {
2073
+ var vml = !svg$1 && (function () {
1956
2074
  try {
1957
2075
  var div = document.createElement('div');
1958
2076
  div.innerHTML = '<v:shape adj="1"/>';
@@ -1968,104 +2086,117 @@
1968
2086
  }());
1969
2087
 
1970
2088
 
2089
+ // @property mac: Boolean; `true` when the browser is running in a Mac platform
2090
+ var mac = navigator.platform.indexOf('Mac') === 0;
2091
+
2092
+ // @property mac: Boolean; `true` when the browser is running in a Linux platform
2093
+ var linux = navigator.platform.indexOf('Linux') === 0;
2094
+
1971
2095
  function userAgentContains(str) {
1972
2096
  return navigator.userAgent.toLowerCase().indexOf(str) >= 0;
1973
- }
1974
-
1975
- var Browser = ({
1976
- ie: ie,
1977
- ielt9: ielt9,
1978
- edge: edge,
1979
- webkit: webkit,
1980
- android: android,
1981
- android23: android23,
1982
- androidStock: androidStock,
1983
- opera: opera,
1984
- chrome: chrome,
1985
- gecko: gecko,
1986
- safari: safari,
1987
- phantom: phantom,
1988
- opera12: opera12,
1989
- win: win,
1990
- ie3d: ie3d,
1991
- webkit3d: webkit3d,
1992
- gecko3d: gecko3d,
1993
- any3d: any3d,
1994
- mobile: mobile,
1995
- mobileWebkit: mobileWebkit,
1996
- mobileWebkit3d: mobileWebkit3d,
1997
- msPointer: msPointer,
1998
- pointer: pointer,
1999
- touch: touch,
2000
- mobileOpera: mobileOpera,
2001
- mobileGecko: mobileGecko,
2002
- retina: retina,
2003
- passiveEvents: passiveEvents,
2004
- canvas: canvas,
2005
- svg: svg,
2006
- vml: vml
2007
- });
2097
+ }
2098
+
2099
+
2100
+ var Browser = {
2101
+ ie: ie,
2102
+ ielt9: ielt9,
2103
+ edge: edge,
2104
+ webkit: webkit,
2105
+ android: android,
2106
+ android23: android23,
2107
+ androidStock: androidStock,
2108
+ opera: opera,
2109
+ chrome: chrome,
2110
+ gecko: gecko,
2111
+ safari: safari,
2112
+ phantom: phantom,
2113
+ opera12: opera12,
2114
+ win: win,
2115
+ ie3d: ie3d,
2116
+ webkit3d: webkit3d,
2117
+ gecko3d: gecko3d,
2118
+ any3d: any3d,
2119
+ mobile: mobile,
2120
+ mobileWebkit: mobileWebkit,
2121
+ mobileWebkit3d: mobileWebkit3d,
2122
+ msPointer: msPointer,
2123
+ pointer: pointer,
2124
+ touch: touch,
2125
+ touchNative: touchNative,
2126
+ mobileOpera: mobileOpera,
2127
+ mobileGecko: mobileGecko,
2128
+ retina: retina,
2129
+ passiveEvents: passiveEvents,
2130
+ canvas: canvas$1,
2131
+ svg: svg$1,
2132
+ vml: vml,
2133
+ inlineSvg: inlineSvg,
2134
+ mac: mac,
2135
+ linux: linux
2136
+ };
2008
2137
 
2009
2138
  /*
2010
2139
  * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
2011
2140
  */
2012
2141
 
2013
-
2014
- var POINTER_DOWN = msPointer ? 'MSPointerDown' : 'pointerdown';
2015
- var POINTER_MOVE = msPointer ? 'MSPointerMove' : 'pointermove';
2016
- var POINTER_UP = msPointer ? 'MSPointerUp' : 'pointerup';
2017
- var POINTER_CANCEL = msPointer ? 'MSPointerCancel' : 'pointercancel';
2018
-
2142
+ var POINTER_DOWN = Browser.msPointer ? 'MSPointerDown' : 'pointerdown';
2143
+ var POINTER_MOVE = Browser.msPointer ? 'MSPointerMove' : 'pointermove';
2144
+ var POINTER_UP = Browser.msPointer ? 'MSPointerUp' : 'pointerup';
2145
+ var POINTER_CANCEL = Browser.msPointer ? 'MSPointerCancel' : 'pointercancel';
2146
+ var pEvent = {
2147
+ touchstart : POINTER_DOWN,
2148
+ touchmove : POINTER_MOVE,
2149
+ touchend : POINTER_UP,
2150
+ touchcancel : POINTER_CANCEL
2151
+ };
2152
+ var handle = {
2153
+ touchstart : _onPointerStart,
2154
+ touchmove : _handlePointer,
2155
+ touchend : _handlePointer,
2156
+ touchcancel : _handlePointer
2157
+ };
2019
2158
  var _pointers = {};
2020
2159
  var _pointerDocListener = false;
2021
2160
 
2022
2161
  // Provides a touch events wrapper for (ms)pointer events.
2023
- // ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
2162
+ // ref https://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
2024
2163
 
2025
- function addPointerListener(obj, type, handler, id) {
2164
+ function addPointerListener(obj, type, handler) {
2026
2165
  if (type === 'touchstart') {
2027
- _addPointerStart(obj, handler, id);
2028
-
2029
- } else if (type === 'touchmove') {
2030
- _addPointerMove(obj, handler, id);
2031
-
2032
- } else if (type === 'touchend') {
2033
- _addPointerEnd(obj, handler, id);
2166
+ _addPointerDocListener();
2034
2167
  }
2035
-
2036
- return this;
2168
+ if (!handle[type]) {
2169
+ console.warn('wrong event specified:', type);
2170
+ return falseFn;
2171
+ }
2172
+ handler = handle[type].bind(this, handler);
2173
+ obj.addEventListener(pEvent[type], handler, false);
2174
+ return handler;
2037
2175
  }
2038
2176
 
2039
- function removePointerListener(obj, type, id) {
2040
- var handler = obj['_leaflet_' + type + id];
2041
-
2042
- if (type === 'touchstart') {
2043
- obj.removeEventListener(POINTER_DOWN, handler, false);
2044
-
2045
- } else if (type === 'touchmove') {
2046
- obj.removeEventListener(POINTER_MOVE, handler, false);
2047
-
2048
- } else if (type === 'touchend') {
2049
- obj.removeEventListener(POINTER_UP, handler, false);
2050
- obj.removeEventListener(POINTER_CANCEL, handler, false);
2177
+ function removePointerListener(obj, type, handler) {
2178
+ if (!pEvent[type]) {
2179
+ console.warn('wrong event specified:', type);
2180
+ return;
2051
2181
  }
2052
-
2053
- return this;
2182
+ obj.removeEventListener(pEvent[type], handler, false);
2054
2183
  }
2055
2184
 
2056
- function _addPointerStart(obj, handler, id) {
2057
- var onDown = bind(function (e) {
2058
- // IE10 specific: MsTouch needs preventDefault. See #2000
2059
- if (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) {
2060
- preventDefault(e);
2061
- }
2185
+ function _globalPointerDown(e) {
2186
+ _pointers[e.pointerId] = e;
2187
+ }
2062
2188
 
2063
- _handlePointer(e, handler);
2064
- });
2189
+ function _globalPointerMove(e) {
2190
+ if (_pointers[e.pointerId]) {
2191
+ _pointers[e.pointerId] = e;
2192
+ }
2193
+ }
2065
2194
 
2066
- obj['_leaflet_touchstart' + id] = onDown;
2067
- obj.addEventListener(POINTER_DOWN, onDown, false);
2195
+ function _globalPointerUp(e) {
2196
+ delete _pointers[e.pointerId];
2197
+ }
2068
2198
 
2199
+ function _addPointerDocListener() {
2069
2200
  // need to keep track of what pointers and how many are active to provide e.touches emulation
2070
2201
  if (!_pointerDocListener) {
2071
2202
  // we listen document as any drags that end by moving the touch off the screen get fired there
@@ -2078,21 +2209,9 @@
2078
2209
  }
2079
2210
  }
2080
2211
 
2081
- function _globalPointerDown(e) {
2082
- _pointers[e.pointerId] = e;
2083
- }
2084
-
2085
- function _globalPointerMove(e) {
2086
- if (_pointers[e.pointerId]) {
2087
- _pointers[e.pointerId] = e;
2088
- }
2089
- }
2090
-
2091
- function _globalPointerUp(e) {
2092
- delete _pointers[e.pointerId];
2093
- }
2212
+ function _handlePointer(handler, e) {
2213
+ if (e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse')) { return; }
2094
2214
 
2095
- function _handlePointer(e, handler) {
2096
2215
  e.touches = [];
2097
2216
  for (var i in _pointers) {
2098
2217
  e.touches.push(_pointers[i]);
@@ -2102,108 +2221,102 @@
2102
2221
  handler(e);
2103
2222
  }
2104
2223
 
2105
- function _addPointerMove(obj, handler, id) {
2106
- var onMove = function (e) {
2107
- // don't fire touch moves when mouse isn't down
2108
- if ((e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse')) && e.buttons === 0) {
2109
- return;
2110
- }
2111
-
2112
- _handlePointer(e, handler);
2113
- };
2114
-
2115
- obj['_leaflet_touchmove' + id] = onMove;
2116
- obj.addEventListener(POINTER_MOVE, onMove, false);
2117
- }
2118
-
2119
- function _addPointerEnd(obj, handler, id) {
2120
- var onUp = function (e) {
2121
- _handlePointer(e, handler);
2122
- };
2123
-
2124
- obj['_leaflet_touchend' + id] = onUp;
2125
- obj.addEventListener(POINTER_UP, onUp, false);
2126
- obj.addEventListener(POINTER_CANCEL, onUp, false);
2224
+ function _onPointerStart(handler, e) {
2225
+ // IE10 specific: MsTouch needs preventDefault. See #2000
2226
+ if (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) {
2227
+ preventDefault(e);
2228
+ }
2229
+ _handlePointer(handler, e);
2127
2230
  }
2128
2231
 
2129
2232
  /*
2130
2233
  * Extends the event handling code with double tap support for mobile browsers.
2234
+ *
2235
+ * Note: currently most browsers fire native dblclick, with only a few exceptions
2236
+ * (see https://github.com/Leaflet/Leaflet/issues/7012#issuecomment-595087386)
2131
2237
  */
2132
2238
 
2133
- var _touchstart = msPointer ? 'MSPointerDown' : pointer ? 'pointerdown' : 'touchstart';
2134
- var _touchend = msPointer ? 'MSPointerUp' : pointer ? 'pointerup' : 'touchend';
2135
- var _pre = '_leaflet_';
2136
-
2137
- // inspired by Zepto touch code by Thomas Fuchs
2138
- function addDoubleTapListener(obj, handler, id) {
2139
- var last, touch$$1,
2140
- doubleTap = false,
2141
- delay = 250;
2142
-
2143
- function onTouchStart(e) {
2239
+ function makeDblclick(event) {
2240
+ // in modern browsers `type` cannot be just overridden:
2241
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only
2242
+ var newEvent = {},
2243
+ prop, i;
2244
+ for (i in event) {
2245
+ prop = event[i];
2246
+ newEvent[i] = prop && prop.bind ? prop.bind(event) : prop;
2247
+ }
2248
+ event = newEvent;
2249
+ newEvent.type = 'dblclick';
2250
+ newEvent.detail = 2;
2251
+ newEvent.isTrusted = false;
2252
+ newEvent._simulated = true; // for debug purposes
2253
+ return newEvent;
2254
+ }
2144
2255
 
2145
- if (pointer) {
2146
- if (!e.isPrimary) { return; }
2147
- if (e.pointerType === 'mouse') { return; } // mouse fires native dblclick
2148
- } else if (e.touches.length > 1) {
2256
+ var delay = 200;
2257
+ function addDoubleTapListener(obj, handler) {
2258
+ // Most browsers handle double tap natively
2259
+ obj.addEventListener('dblclick', handler);
2260
+
2261
+ // On some platforms the browser doesn't fire native dblclicks for touch events.
2262
+ // It seems that in all such cases `detail` property of `click` event is always `1`.
2263
+ // So here we rely on that fact to avoid excessive 'dblclick' simulation when not needed.
2264
+ var last = 0,
2265
+ detail;
2266
+ function simDblclick(e) {
2267
+ if (e.detail !== 1) {
2268
+ detail = e.detail; // keep in sync to avoid false dblclick in some cases
2149
2269
  return;
2150
2270
  }
2151
2271
 
2152
- var now = Date.now(),
2153
- delta = now - (last || now);
2272
+ if (e.pointerType === 'mouse' ||
2273
+ (e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents)) {
2154
2274
 
2155
- touch$$1 = e.touches ? e.touches[0] : e;
2156
- doubleTap = (delta > 0 && delta <= delay);
2157
- last = now;
2158
- }
2275
+ return;
2276
+ }
2159
2277
 
2160
- function onTouchEnd(e) {
2161
- if (doubleTap && !touch$$1.cancelBubble) {
2162
- if (pointer) {
2163
- if (e.pointerType === 'mouse') { return; }
2164
- // work around .type being readonly with MSPointer* events
2165
- var newTouch = {},
2166
- prop, i;
2278
+ // When clicking on an <input>, the browser generates a click on its
2279
+ // <label> (and vice versa) triggering two clicks in quick succession.
2280
+ // This ignores clicks on elements which are a label with a 'for'
2281
+ // attribute (or children of such a label), but not children of
2282
+ // a <input>.
2283
+ var path = getPropagationPath(e);
2284
+ if (path.some(function (el) {
2285
+ return el instanceof HTMLLabelElement && el.attributes.for;
2286
+ }) &&
2287
+ !path.some(function (el) {
2288
+ return (
2289
+ el instanceof HTMLInputElement ||
2290
+ el instanceof HTMLSelectElement
2291
+ );
2292
+ })
2293
+ ) {
2294
+ return;
2295
+ }
2167
2296
 
2168
- for (i in touch$$1) {
2169
- prop = touch$$1[i];
2170
- newTouch[i] = prop && prop.bind ? prop.bind(touch$$1) : prop;
2171
- }
2172
- touch$$1 = newTouch;
2297
+ var now = Date.now();
2298
+ if (now - last <= delay) {
2299
+ detail++;
2300
+ if (detail === 2) {
2301
+ handler(makeDblclick(e));
2173
2302
  }
2174
- touch$$1.type = 'dblclick';
2175
- touch$$1.button = 0;
2176
- handler(touch$$1);
2177
- last = null;
2303
+ } else {
2304
+ detail = 1;
2178
2305
  }
2306
+ last = now;
2179
2307
  }
2180
2308
 
2181
- obj[_pre + _touchstart + id] = onTouchStart;
2182
- obj[_pre + _touchend + id] = onTouchEnd;
2183
- obj[_pre + 'dblclick' + id] = handler;
2309
+ obj.addEventListener('click', simDblclick);
2184
2310
 
2185
- obj.addEventListener(_touchstart, onTouchStart, passiveEvents ? {passive: false} : false);
2186
- obj.addEventListener(_touchend, onTouchEnd, passiveEvents ? {passive: false} : false);
2187
-
2188
- // On some platforms (notably, chrome<55 on win10 + touchscreen + mouse),
2189
- // the browser doesn't fire touchend/pointerup events but does fire
2190
- // native dblclicks. See #4127.
2191
- // Edge 14 also fires native dblclicks, but only for pointerType mouse, see #5180.
2192
- obj.addEventListener('dblclick', handler, false);
2193
-
2194
- return this;
2311
+ return {
2312
+ dblclick: handler,
2313
+ simDblclick: simDblclick
2314
+ };
2195
2315
  }
2196
2316
 
2197
- function removeDoubleTapListener(obj, id) {
2198
- var touchstart = obj[_pre + _touchstart + id],
2199
- touchend = obj[_pre + _touchend + id],
2200
- dblclick = obj[_pre + 'dblclick' + id];
2201
-
2202
- obj.removeEventListener(_touchstart, touchstart, passiveEvents ? {passive: false} : false);
2203
- obj.removeEventListener(_touchend, touchend, passiveEvents ? {passive: false} : false);
2204
- obj.removeEventListener('dblclick', dblclick, false);
2205
-
2206
- return this;
2317
+ function removeDoubleTapListener(obj, handlers) {
2318
+ obj.removeEventListener('dblclick', handlers.dblclick);
2319
+ obj.removeEventListener('click', handlers.simDblclick);
2207
2320
  }
2208
2321
 
2209
2322
  /*
@@ -2417,7 +2530,7 @@
2417
2530
  var pos = offset || new Point(0, 0);
2418
2531
 
2419
2532
  el.style[TRANSFORM] =
2420
- (ie3d ?
2533
+ (Browser.ie3d ?
2421
2534
  'translate(' + pos.x + 'px,' + pos.y + 'px)' :
2422
2535
  'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +
2423
2536
  (scale ? ' scale(' + scale + ')' : '');
@@ -2433,7 +2546,7 @@
2433
2546
  el._leaflet_pos = point;
2434
2547
  /* eslint-enable */
2435
2548
 
2436
- if (any3d) {
2549
+ if (Browser.any3d) {
2437
2550
  setTransform(el, point);
2438
2551
  } else {
2439
2552
  el.style.left = point.x + 'px';
@@ -2513,8 +2626,8 @@
2513
2626
  if (!element.style) { return; }
2514
2627
  restoreOutline();
2515
2628
  _outlineElement = element;
2516
- _outlineStyle = element.style.outline;
2517
- element.style.outline = 'none';
2629
+ _outlineStyle = element.style.outlineStyle;
2630
+ element.style.outlineStyle = 'none';
2518
2631
  on(window, 'keydown', restoreOutline);
2519
2632
  }
2520
2633
 
@@ -2522,7 +2635,7 @@
2522
2635
  // Cancels the effects of a previous [`L.DomUtil.preventOutline`]().
2523
2636
  function restoreOutline() {
2524
2637
  if (!_outlineElement) { return; }
2525
- _outlineElement.style.outline = _outlineStyle;
2638
+ _outlineElement.style.outlineStyle = _outlineStyle;
2526
2639
  _outlineElement = undefined;
2527
2640
  _outlineStyle = undefined;
2528
2641
  off(window, 'keydown', restoreOutline);
@@ -2551,7 +2664,8 @@
2551
2664
  };
2552
2665
  }
2553
2666
 
2554
- var DomUtil = ({
2667
+ var DomUtil = {
2668
+ __proto__: null,
2555
2669
  TRANSFORM: TRANSFORM,
2556
2670
  TRANSITION: TRANSITION,
2557
2671
  TRANSITION_END: TRANSITION_END,
@@ -2572,15 +2686,15 @@
2572
2686
  setTransform: setTransform,
2573
2687
  setPosition: setPosition,
2574
2688
  getPosition: getPosition,
2575
- disableTextSelection: disableTextSelection,
2576
- enableTextSelection: enableTextSelection,
2689
+ get disableTextSelection () { return disableTextSelection; },
2690
+ get enableTextSelection () { return enableTextSelection; },
2577
2691
  disableImageDrag: disableImageDrag,
2578
2692
  enableImageDrag: enableImageDrag,
2579
2693
  preventOutline: preventOutline,
2580
2694
  restoreOutline: restoreOutline,
2581
2695
  getSizedParentNode: getSizedParentNode,
2582
2696
  getScale: getScale
2583
- });
2697
+ };
2584
2698
 
2585
2699
  /*
2586
2700
  * @namespace DomEvent
@@ -2600,7 +2714,7 @@
2600
2714
  // Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
2601
2715
  function on(obj, types, fn, context) {
2602
2716
 
2603
- if (typeof types === 'object') {
2717
+ if (types && typeof types === 'object') {
2604
2718
  for (var type in types) {
2605
2719
  addOne(obj, type, types[type], fn);
2606
2720
  }
@@ -2625,32 +2739,48 @@
2625
2739
  // @alternative
2626
2740
  // @function off(el: HTMLElement, eventMap: Object, context?: Object): this
2627
2741
  // Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
2742
+
2743
+ // @alternative
2744
+ // @function off(el: HTMLElement, types: String): this
2745
+ // Removes all previously added listeners of given types.
2746
+
2747
+ // @alternative
2748
+ // @function off(el: HTMLElement): this
2749
+ // Removes all previously added listeners from given HTMLElement
2628
2750
  function off(obj, types, fn, context) {
2629
2751
 
2630
- if (typeof types === 'object') {
2752
+ if (arguments.length === 1) {
2753
+ batchRemove(obj);
2754
+ delete obj[eventsKey];
2755
+
2756
+ } else if (types && typeof types === 'object') {
2631
2757
  for (var type in types) {
2632
2758
  removeOne(obj, type, types[type], fn);
2633
2759
  }
2634
- } else if (types) {
2635
- types = splitWords(types);
2636
2760
 
2637
- for (var i = 0, len = types.length; i < len; i++) {
2638
- removeOne(obj, types[i], fn, context);
2639
- }
2640
2761
  } else {
2641
- for (var j in obj[eventsKey]) {
2642
- removeOne(obj, j, obj[eventsKey][j]);
2762
+ types = splitWords(types);
2763
+
2764
+ if (arguments.length === 2) {
2765
+ batchRemove(obj, function (type) {
2766
+ return indexOf(types, type) !== -1;
2767
+ });
2768
+ } else {
2769
+ for (var i = 0, len = types.length; i < len; i++) {
2770
+ removeOne(obj, types[i], fn, context);
2771
+ }
2643
2772
  }
2644
- delete obj[eventsKey];
2645
2773
  }
2646
2774
 
2647
2775
  return this;
2648
2776
  }
2649
2777
 
2650
- function browserFiresNativeDblClick() {
2651
- // See https://github.com/w3c/pointerevents/issues/171
2652
- if (pointer) {
2653
- return !(edge || safari);
2778
+ function batchRemove(obj, filterFn) {
2779
+ for (var id in obj[eventsKey]) {
2780
+ var type = id.split(/\d/)[0];
2781
+ if (!filterFn || filterFn(type)) {
2782
+ removeOne(obj, type, null, null, id);
2783
+ }
2654
2784
  }
2655
2785
  }
2656
2786
 
@@ -2671,17 +2801,17 @@
2671
2801
 
2672
2802
  var originalHandler = handler;
2673
2803
 
2674
- if (pointer && type.indexOf('touch') === 0) {
2804
+ if (!Browser.touchNative && Browser.pointer && type.indexOf('touch') === 0) {
2675
2805
  // Needs DomEvent.Pointer.js
2676
- addPointerListener(obj, type, handler, id);
2806
+ handler = addPointerListener(obj, type, handler);
2677
2807
 
2678
- } else if (touch && (type === 'dblclick') && !browserFiresNativeDblClick()) {
2679
- addDoubleTapListener(obj, handler, id);
2808
+ } else if (Browser.touch && (type === 'dblclick')) {
2809
+ handler = addDoubleTapListener(obj, handler);
2680
2810
 
2681
2811
  } else if ('addEventListener' in obj) {
2682
2812
 
2683
2813
  if (type === 'touchstart' || type === 'touchmove' || type === 'wheel' || type === 'mousewheel') {
2684
- obj.addEventListener(mouseSubst[type] || type, handler, passiveEvents ? {passive: false} : false);
2814
+ obj.addEventListener(mouseSubst[type] || type, handler, Browser.passiveEvents ? {passive: false} : false);
2685
2815
 
2686
2816
  } else if (type === 'mouseenter' || type === 'mouseleave') {
2687
2817
  handler = function (e) {
@@ -2696,7 +2826,7 @@
2696
2826
  obj.addEventListener(type, originalHandler, false);
2697
2827
  }
2698
2828
 
2699
- } else if ('attachEvent' in obj) {
2829
+ } else {
2700
2830
  obj.attachEvent('on' + type, handler);
2701
2831
  }
2702
2832
 
@@ -2704,24 +2834,23 @@
2704
2834
  obj[eventsKey][id] = handler;
2705
2835
  }
2706
2836
 
2707
- function removeOne(obj, type, fn, context) {
2708
-
2709
- var id = type + stamp(fn) + (context ? '_' + stamp(context) : ''),
2710
- handler = obj[eventsKey] && obj[eventsKey][id];
2837
+ function removeOne(obj, type, fn, context, id) {
2838
+ id = id || type + stamp(fn) + (context ? '_' + stamp(context) : '');
2839
+ var handler = obj[eventsKey] && obj[eventsKey][id];
2711
2840
 
2712
2841
  if (!handler) { return this; }
2713
2842
 
2714
- if (pointer && type.indexOf('touch') === 0) {
2715
- removePointerListener(obj, type, id);
2843
+ if (!Browser.touchNative && Browser.pointer && type.indexOf('touch') === 0) {
2844
+ removePointerListener(obj, type, handler);
2716
2845
 
2717
- } else if (touch && (type === 'dblclick') && !browserFiresNativeDblClick()) {
2718
- removeDoubleTapListener(obj, id);
2846
+ } else if (Browser.touch && (type === 'dblclick')) {
2847
+ removeDoubleTapListener(obj, handler);
2719
2848
 
2720
2849
  } else if ('removeEventListener' in obj) {
2721
2850
 
2722
2851
  obj.removeEventListener(mouseSubst[type] || type, handler, false);
2723
2852
 
2724
- } else if ('detachEvent' in obj) {
2853
+ } else {
2725
2854
  obj.detachEvent('on' + type, handler);
2726
2855
  }
2727
2856
 
@@ -2744,7 +2873,6 @@
2744
2873
  } else {
2745
2874
  e.cancelBubble = true;
2746
2875
  }
2747
- skipped(e);
2748
2876
 
2749
2877
  return this;
2750
2878
  }
@@ -2757,11 +2885,11 @@
2757
2885
  }
2758
2886
 
2759
2887
  // @function disableClickPropagation(el: HTMLElement): this
2760
- // Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`,
2888
+ // Adds `stopPropagation` to the element's `'click'`, `'dblclick'`, `'contextmenu'`,
2761
2889
  // `'mousedown'` and `'touchstart'` events (plus browser variants).
2762
2890
  function disableClickPropagation(el) {
2763
- on(el, 'mousedown touchstart dblclick', stopPropagation);
2764
- addOne(el, 'click', fakeStop);
2891
+ on(el, 'mousedown touchstart dblclick contextmenu', stopPropagation);
2892
+ el['_leaflet_disable_click'] = true;
2765
2893
  return this;
2766
2894
  }
2767
2895
 
@@ -2787,6 +2915,26 @@
2787
2915
  return this;
2788
2916
  }
2789
2917
 
2918
+ // @function getPropagationPath(ev: DOMEvent): Array
2919
+ // Compatibility polyfill for [`Event.composedPath()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath).
2920
+ // Returns an array containing the `HTMLElement`s that the given DOM event
2921
+ // should propagate to (if not stopped).
2922
+ function getPropagationPath(ev) {
2923
+ if (ev.composedPath) {
2924
+ return ev.composedPath();
2925
+ }
2926
+
2927
+ var path = [];
2928
+ var el = ev.target;
2929
+
2930
+ while (el) {
2931
+ path.push(el);
2932
+ el = el.parentNode;
2933
+ }
2934
+ return path;
2935
+ }
2936
+
2937
+
2790
2938
  // @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point
2791
2939
  // Gets normalized mouse position from a DOM event relative to the
2792
2940
  // `container` (border excluded) or to the whole page if not specified.
@@ -2806,19 +2954,22 @@
2806
2954
  );
2807
2955
  }
2808
2956
 
2809
- // Chrome on Win scrolls double the pixels as in other platforms (see #4538),
2810
- // and Firefox scrolls device pixels, not CSS pixels
2811
- var wheelPxFactor =
2812
- (win && chrome) ? 2 * window.devicePixelRatio :
2813
- gecko ? window.devicePixelRatio : 1;
2814
2957
 
2958
+ // except , Safari and
2959
+ // We need double the scroll pixels (see #7403 and #4538) for all Browsers
2960
+ // except OSX (Mac) -> 3x, Chrome running on Linux 1x
2961
+
2962
+ var wheelPxFactor =
2963
+ (Browser.linux && Browser.chrome) ? window.devicePixelRatio :
2964
+ Browser.mac ? window.devicePixelRatio * 3 :
2965
+ window.devicePixelRatio > 0 ? 2 * window.devicePixelRatio : 1;
2815
2966
  // @function getWheelDelta(ev: DOMEvent): Number
2816
2967
  // Gets normalized wheel delta from a wheel DOM event, in vertical
2817
2968
  // pixels scrolled (negative if scrolling down).
2818
2969
  // Events from pointing devices without precise scrolling are mapped to
2819
2970
  // a best guess of 60 pixels.
2820
2971
  function getWheelDelta(e) {
2821
- return (edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta
2972
+ return (Browser.edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta
2822
2973
  (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels
2823
2974
  (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines
2824
2975
  (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages
@@ -2829,20 +2980,6 @@
2829
2980
  0;
2830
2981
  }
2831
2982
 
2832
- var skipEvents = {};
2833
-
2834
- function fakeStop(e) {
2835
- // fakes stopPropagation by setting a special event flag, checked/reset with skipped(e)
2836
- skipEvents[e.type] = true;
2837
- }
2838
-
2839
- function skipped(e) {
2840
- var events = skipEvents[e.type];
2841
- // reset when checking, as it's only used in map container and propagates outside of the map
2842
- skipEvents[e.type] = false;
2843
- return events;
2844
- }
2845
-
2846
2983
  // check if element really left/entered the event target (for mouseenter/mouseleave)
2847
2984
  function isExternalTarget(el, e) {
2848
2985
 
@@ -2860,7 +2997,8 @@
2860
2997
  return (related !== el);
2861
2998
  }
2862
2999
 
2863
- var DomEvent = ({
3000
+ var DomEvent = {
3001
+ __proto__: null,
2864
3002
  on: on,
2865
3003
  off: off,
2866
3004
  stopPropagation: stopPropagation,
@@ -2868,14 +3006,13 @@
2868
3006
  disableClickPropagation: disableClickPropagation,
2869
3007
  preventDefault: preventDefault,
2870
3008
  stop: stop,
3009
+ getPropagationPath: getPropagationPath,
2871
3010
  getMousePosition: getMousePosition,
2872
3011
  getWheelDelta: getWheelDelta,
2873
- fakeStop: fakeStop,
2874
- skipped: skipped,
2875
3012
  isExternalTarget: isExternalTarget,
2876
3013
  addListener: on,
2877
3014
  removeListener: off
2878
- });
3015
+ };
2879
3016
 
2880
3017
  /*
2881
3018
  * @class PosAnimation
@@ -2885,8 +3022,21 @@
2885
3022
  *
2886
3023
  * @example
2887
3024
  * ```js
2888
- * var fx = new L.PosAnimation();
2889
- * fx.run(el, [300, 500], 0.5);
3025
+ * var myPositionMarker = L.marker([48.864716, 2.294694]).addTo(map);
3026
+ *
3027
+ * myPositionMarker.on("click", function() {
3028
+ * var pos = map.latLngToLayerPoint(myPositionMarker.getLatLng());
3029
+ * pos.y -= 25;
3030
+ * var fx = new L.PosAnimation();
3031
+ *
3032
+ * fx.once('end',function() {
3033
+ * pos.y += 25;
3034
+ * fx.run(myPositionMarker._icon, pos, 0.8);
3035
+ * });
3036
+ *
3037
+ * fx.run(myPositionMarker._icon, pos, 0.3);
3038
+ * });
3039
+ *
2890
3040
  * ```
2891
3041
  *
2892
3042
  * @constructor L.PosAnimation()
@@ -2899,7 +3049,7 @@
2899
3049
  // @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)
2900
3050
  // Run an animation of a given element to a new position, optionally setting
2901
3051
  // duration in seconds (`0.25` by default) and easing linearity factor (3rd
2902
- // argument of the [cubic bezier curve](http://cubic-bezier.com/#0,0,.5,1),
3052
+ // argument of the [cubic bezier curve](https://cubic-bezier.com/#0,0,.5,1),
2903
3053
  // `0.5` by default).
2904
3054
  run: function (el, newPos, duration, easeLinearity) {
2905
3055
  this.stop();
@@ -3119,7 +3269,7 @@
3119
3269
  this.callInitHooks();
3120
3270
 
3121
3271
  // don't animate on browsers without hardware-accelerated transitions or old Android/Opera
3122
- this._zoomAnimated = TRANSITION && any3d && !mobileOpera &&
3272
+ this._zoomAnimated = TRANSITION && Browser.any3d && !Browser.mobileOpera &&
3123
3273
  this.options.zoomAnimation;
3124
3274
 
3125
3275
  // zoom transitions run with the same duration for all layers, so if one of transitionend events
@@ -3166,7 +3316,7 @@
3166
3316
  }
3167
3317
 
3168
3318
  // animation didn't start, just reset the map view
3169
- this._resetView(center, zoom);
3319
+ this._resetView(center, zoom, options.pan && options.pan.noMoveStart);
3170
3320
 
3171
3321
  return this;
3172
3322
  },
@@ -3184,14 +3334,14 @@
3184
3334
  // @method zoomIn(delta?: Number, options?: Zoom options): this
3185
3335
  // Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
3186
3336
  zoomIn: function (delta, options) {
3187
- delta = delta || (any3d ? this.options.zoomDelta : 1);
3337
+ delta = delta || (Browser.any3d ? this.options.zoomDelta : 1);
3188
3338
  return this.setZoom(this._zoom + delta, options);
3189
3339
  },
3190
3340
 
3191
3341
  // @method zoomOut(delta?: Number, options?: Zoom options): this
3192
3342
  // Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
3193
3343
  zoomOut: function (delta, options) {
3194
- delta = delta || (any3d ? this.options.zoomDelta : 1);
3344
+ delta = delta || (Browser.any3d ? this.options.zoomDelta : 1);
3195
3345
  return this.setZoom(this._zoom - delta, options);
3196
3346
  },
3197
3347
 
@@ -3321,7 +3471,7 @@
3321
3471
  flyTo: function (targetCenter, targetZoom, options) {
3322
3472
 
3323
3473
  options = options || {};
3324
- if (options.animate === false || !any3d) {
3474
+ if (options.animate === false || !Browser.any3d) {
3325
3475
  return this.setView(targetCenter, targetZoom, options);
3326
3476
  }
3327
3477
 
@@ -3409,11 +3559,13 @@
3409
3559
  setMaxBounds: function (bounds) {
3410
3560
  bounds = toLatLngBounds(bounds);
3411
3561
 
3562
+ if (this.listens('moveend', this._panInsideMaxBounds)) {
3563
+ this.off('moveend', this._panInsideMaxBounds);
3564
+ }
3565
+
3412
3566
  if (!bounds.isValid()) {
3413
3567
  this.options.maxBounds = null;
3414
- return this.off('moveend', this._panInsideMaxBounds);
3415
- } else if (this.options.maxBounds) {
3416
- this.off('moveend', this._panInsideMaxBounds);
3568
+ return this;
3417
3569
  }
3418
3570
 
3419
3571
  this.options.maxBounds = bounds;
@@ -3474,10 +3626,9 @@
3474
3626
  return this;
3475
3627
  },
3476
3628
 
3477
- // @method panInside(latlng: LatLng, options?: options): this
3629
+ // @method panInside(latlng: LatLng, options?: padding options): this
3478
3630
  // Pans the map the minimum amount to make the `latlng` visible. Use
3479
- // `padding`, `paddingTopLeft` and `paddingTopRight` options to fit
3480
- // the display to more restricted bounds, like [`fitBounds`](#map-fitbounds).
3631
+ // padding options to fit the display to more restricted bounds.
3481
3632
  // If `latlng` is already within the (optionally padded) display bounds,
3482
3633
  // the map will not be panned.
3483
3634
  panInside: function (latlng, options) {
@@ -3485,35 +3636,19 @@
3485
3636
 
3486
3637
  var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
3487
3638
  paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
3488
- center = this.getCenter(),
3489
- pixelCenter = this.project(center),
3639
+ pixelCenter = this.project(this.getCenter()),
3490
3640
  pixelPoint = this.project(latlng),
3491
3641
  pixelBounds = this.getPixelBounds(),
3492
- halfPixelBounds = pixelBounds.getSize().divideBy(2),
3493
- paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]);
3642
+ paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),
3643
+ paddedSize = paddedBounds.getSize();
3494
3644
 
3495
3645
  if (!paddedBounds.contains(pixelPoint)) {
3496
3646
  this._enforcingBounds = true;
3497
- var diff = pixelCenter.subtract(pixelPoint),
3498
- newCenter = toPoint(pixelPoint.x + diff.x, pixelPoint.y + diff.y);
3499
-
3500
- if (pixelPoint.x < paddedBounds.min.x || pixelPoint.x > paddedBounds.max.x) {
3501
- newCenter.x = pixelCenter.x - diff.x;
3502
- if (diff.x > 0) {
3503
- newCenter.x += halfPixelBounds.x - paddingTL.x;
3504
- } else {
3505
- newCenter.x -= halfPixelBounds.x - paddingBR.x;
3506
- }
3507
- }
3508
- if (pixelPoint.y < paddedBounds.min.y || pixelPoint.y > paddedBounds.max.y) {
3509
- newCenter.y = pixelCenter.y - diff.y;
3510
- if (diff.y > 0) {
3511
- newCenter.y += halfPixelBounds.y - paddingTL.y;
3512
- } else {
3513
- newCenter.y -= halfPixelBounds.y - paddingBR.y;
3514
- }
3515
- }
3516
- this.panTo(this.unproject(newCenter), options);
3647
+ var centerOffset = pixelPoint.subtract(paddedBounds.getCenter());
3648
+ var offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);
3649
+ pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;
3650
+ pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;
3651
+ this.panTo(this.unproject(pixelCenter), options);
3517
3652
  this._enforcingBounds = false;
3518
3653
  }
3519
3654
  return this;
@@ -3644,6 +3779,8 @@
3644
3779
  },
3645
3780
 
3646
3781
  _handleGeolocationError: function (error) {
3782
+ if (!this._container._leaflet_id) { return; }
3783
+
3647
3784
  var c = error.code,
3648
3785
  message = error.message ||
3649
3786
  (c === 1 ? 'permission denied' :
@@ -3663,6 +3800,8 @@
3663
3800
  },
3664
3801
 
3665
3802
  _handleGeolocationResponse: function (pos) {
3803
+ if (!this._container._leaflet_id) { return; }
3804
+
3666
3805
  var lat = pos.coords.latitude,
3667
3806
  lng = pos.coords.longitude,
3668
3807
  latlng = new LatLng(lat, lng),
@@ -3715,7 +3854,7 @@
3715
3854
  remove: function () {
3716
3855
 
3717
3856
  this._initEvents(true);
3718
- this.off('moveend', this._panInsideMaxBounds);
3857
+ if (this.options.maxBounds) { this.off('moveend', this._panInsideMaxBounds); }
3719
3858
 
3720
3859
  if (this._containerId !== this._container._leaflet_id) {
3721
3860
  throw new Error('Map container is being reused by another instance');
@@ -3796,7 +3935,7 @@
3796
3935
  this._checkIfLoaded();
3797
3936
 
3798
3937
  if (this._lastCenter && !this._moved()) {
3799
- return this._lastCenter;
3938
+ return this._lastCenter.clone();
3800
3939
  }
3801
3940
  return this.layerPointToLatLng(this._getCenterLayerPoint());
3802
3941
  },
@@ -3847,7 +3986,7 @@
3847
3986
  se = bounds.getSouthEast(),
3848
3987
  size = this.getSize().subtract(padding),
3849
3988
  boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
3850
- snap = any3d ? this.options.zoomSnap : 1,
3989
+ snap = Browser.any3d ? this.options.zoomSnap : 1,
3851
3990
  scalex = size.x / boundsSize.x,
3852
3991
  scaley = size.y / boundsSize.y,
3853
3992
  scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
@@ -4075,18 +4214,18 @@
4075
4214
  _initLayout: function () {
4076
4215
  var container = this._container;
4077
4216
 
4078
- this._fadeAnimated = this.options.fadeAnimation && any3d;
4217
+ this._fadeAnimated = this.options.fadeAnimation && Browser.any3d;
4079
4218
 
4080
4219
  addClass(container, 'leaflet-container' +
4081
- (touch ? ' leaflet-touch' : '') +
4082
- (retina ? ' leaflet-retina' : '') +
4083
- (ielt9 ? ' leaflet-oldie' : '') +
4084
- (safari ? ' leaflet-safari' : '') +
4220
+ (Browser.touch ? ' leaflet-touch' : '') +
4221
+ (Browser.retina ? ' leaflet-retina' : '') +
4222
+ (Browser.ielt9 ? ' leaflet-oldie' : '') +
4223
+ (Browser.safari ? ' leaflet-safari' : '') +
4085
4224
  (this._fadeAnimated ? ' leaflet-fade-anim' : ''));
4086
4225
 
4087
4226
  var position = getStyle(container, 'position');
4088
4227
 
4089
- if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
4228
+ if (position !== 'absolute' && position !== 'relative' && position !== 'fixed' && position !== 'sticky') {
4090
4229
  container.style.position = 'relative';
4091
4230
  }
4092
4231
 
@@ -4120,11 +4259,11 @@
4120
4259
  // Pane for `GridLayer`s and `TileLayer`s
4121
4260
  this.createPane('tilePane');
4122
4261
  // @pane overlayPane: HTMLElement = 400
4123
- // Pane for overlay shadows (e.g. `Marker` shadows)
4124
- this.createPane('shadowPane');
4125
- // @pane shadowPane: HTMLElement = 500
4126
4262
  // Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s
4127
4263
  this.createPane('overlayPane');
4264
+ // @pane shadowPane: HTMLElement = 500
4265
+ // Pane for overlay shadows (e.g. `Marker` shadows)
4266
+ this.createPane('shadowPane');
4128
4267
  // @pane markerPane: HTMLElement = 600
4129
4268
  // Pane for `Icon`s of `Marker`s
4130
4269
  this.createPane('markerPane');
@@ -4145,7 +4284,7 @@
4145
4284
  // private methods that modify map state
4146
4285
 
4147
4286
  // @section Map state change events
4148
- _resetView: function (center, zoom) {
4287
+ _resetView: function (center, zoom, noMoveStart) {
4149
4288
  setPosition(this._mapPane, new Point(0, 0));
4150
4289
 
4151
4290
  var loading = !this._loaded;
@@ -4156,7 +4295,7 @@
4156
4295
 
4157
4296
  var zoomChanged = this._zoom !== zoom;
4158
4297
  this
4159
- ._moveStart(zoomChanged, false)
4298
+ ._moveStart(zoomChanged, noMoveStart)
4160
4299
  ._move(center, zoom)
4161
4300
  ._moveEnd(zoomChanged);
4162
4301
 
@@ -4187,7 +4326,7 @@
4187
4326
  return this;
4188
4327
  },
4189
4328
 
4190
- _move: function (center, zoom, data) {
4329
+ _move: function (center, zoom, data, supressEvent) {
4191
4330
  if (zoom === undefined) {
4192
4331
  zoom = this._zoom;
4193
4332
  }
@@ -4197,29 +4336,34 @@
4197
4336
  this._lastCenter = center;
4198
4337
  this._pixelOrigin = this._getNewPixelOrigin(center);
4199
4338
 
4200
- // @event zoom: Event
4201
- // Fired repeatedly during any change in zoom level, including zoom
4202
- // and fly animations.
4203
- if (zoomChanged || (data && data.pinch)) { // Always fire 'zoom' if pinching because #3530
4339
+ if (!supressEvent) {
4340
+ // @event zoom: Event
4341
+ // Fired repeatedly during any change in zoom level,
4342
+ // including zoom and fly animations.
4343
+ if (zoomChanged || (data && data.pinch)) { // Always fire 'zoom' if pinching because #3530
4344
+ this.fire('zoom', data);
4345
+ }
4346
+
4347
+ // @event move: Event
4348
+ // Fired repeatedly during any movement of the map,
4349
+ // including pan and fly animations.
4350
+ this.fire('move', data);
4351
+ } else if (data && data.pinch) { // Always fire 'zoom' if pinching because #3530
4204
4352
  this.fire('zoom', data);
4205
4353
  }
4206
-
4207
- // @event move: Event
4208
- // Fired repeatedly during any movement of the map, including pan and
4209
- // fly animations.
4210
- return this.fire('move', data);
4354
+ return this;
4211
4355
  },
4212
4356
 
4213
4357
  _moveEnd: function (zoomChanged) {
4214
4358
  // @event zoomend: Event
4215
- // Fired when the map has changed, after any animations.
4359
+ // Fired when the map zoom changed, after any animations.
4216
4360
  if (zoomChanged) {
4217
4361
  this.fire('zoomend');
4218
4362
  }
4219
4363
 
4220
4364
  // @event moveend: Event
4221
- // Fired when the center of the map stops changing (e.g. user stopped
4222
- // dragging the map).
4365
+ // Fired when the center of the map stops changing
4366
+ // (e.g. user stopped dragging the map or after non-centered zoom).
4223
4367
  return this.fire('moveend');
4224
4368
  },
4225
4369
 
@@ -4254,11 +4398,11 @@
4254
4398
  // DOM event handling
4255
4399
 
4256
4400
  // @section Interaction events
4257
- _initEvents: function (remove$$1) {
4401
+ _initEvents: function (remove) {
4258
4402
  this._targets = {};
4259
4403
  this._targets[stamp(this._container)] = this;
4260
4404
 
4261
- var onOff = remove$$1 ? off : on;
4405
+ var onOff = remove ? off : on;
4262
4406
 
4263
4407
  // @event click: MouseEvent
4264
4408
  // Fired when the user clicks (or taps) the map.
@@ -4294,8 +4438,8 @@
4294
4438
  onOff(window, 'resize', this._onResize, this);
4295
4439
  }
4296
4440
 
4297
- if (any3d && this.options.transform3DLimit) {
4298
- (remove$$1 ? this.off : this.on).call(this, 'moveend', this._onMoveEnd);
4441
+ if (Browser.any3d && this.options.transform3DLimit) {
4442
+ (remove ? this.off : this.on).call(this, 'moveend', this._onMoveEnd);
4299
4443
  }
4300
4444
  },
4301
4445
 
@@ -4314,7 +4458,7 @@
4314
4458
  var pos = this._getMapPanePos();
4315
4459
  if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {
4316
4460
  // https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have
4317
- // a pixel offset on very high values, see: http://jsfiddle.net/dg6r5hhb/
4461
+ // a pixel offset on very high values, see: https://jsfiddle.net/dg6r5hhb/
4318
4462
  this._resetView(this.getCenter(), this.getZoom());
4319
4463
  }
4320
4464
  },
@@ -4328,7 +4472,7 @@
4328
4472
 
4329
4473
  while (src) {
4330
4474
  target = this._targets[stamp(src)];
4331
- if (target && (type === 'click' || type === 'preclick') && !e._simulated && this._draggableMoved(target)) {
4475
+ if (target && (type === 'click' || type === 'preclick') && this._draggableMoved(target)) {
4332
4476
  // Prevent firing click after you just dragged an object.
4333
4477
  dragging = true;
4334
4478
  break;
@@ -4341,20 +4485,30 @@
4341
4485
  if (src === this._container) { break; }
4342
4486
  src = src.parentNode;
4343
4487
  }
4344
- if (!targets.length && !dragging && !isHover && isExternalTarget(src, e)) {
4488
+ if (!targets.length && !dragging && !isHover && this.listens(type, true)) {
4345
4489
  targets = [this];
4346
4490
  }
4347
4491
  return targets;
4348
4492
  },
4349
4493
 
4494
+ _isClickDisabled: function (el) {
4495
+ while (el && el !== this._container) {
4496
+ if (el['_leaflet_disable_click']) { return true; }
4497
+ el = el.parentNode;
4498
+ }
4499
+ },
4500
+
4350
4501
  _handleDOMEvent: function (e) {
4351
- if (!this._loaded || skipped(e)) { return; }
4502
+ var el = (e.target || e.srcElement);
4503
+ if (!this._loaded || el['_leaflet_disable_events'] || e.type === 'click' && this._isClickDisabled(el)) {
4504
+ return;
4505
+ }
4352
4506
 
4353
4507
  var type = e.type;
4354
4508
 
4355
- if (type === 'mousedown' || type === 'keypress' || type === 'keyup' || type === 'keydown') {
4509
+ if (type === 'mousedown') {
4356
4510
  // prevents outline when clicking on keyboard-focusable element
4357
- preventOutline(e.target || e.srcElement);
4511
+ preventOutline(el);
4358
4512
  }
4359
4513
 
4360
4514
  this._fireDOMEvent(e, type);
@@ -4362,7 +4516,7 @@
4362
4516
 
4363
4517
  _mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'],
4364
4518
 
4365
- _fireDOMEvent: function (e, type, targets) {
4519
+ _fireDOMEvent: function (e, type, canvasTargets) {
4366
4520
 
4367
4521
  if (e.type === 'click') {
4368
4522
  // Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).
@@ -4372,21 +4526,29 @@
4372
4526
  // handlers start running).
4373
4527
  var synth = extend({}, e);
4374
4528
  synth.type = 'preclick';
4375
- this._fireDOMEvent(synth, synth.type, targets);
4529
+ this._fireDOMEvent(synth, synth.type, canvasTargets);
4376
4530
  }
4377
4531
 
4378
- if (e._stopped) { return; }
4379
-
4380
4532
  // Find the layer the event is propagating from and its parents.
4381
- targets = (targets || []).concat(this._findEventTargets(e, type));
4533
+ var targets = this._findEventTargets(e, type);
4534
+
4535
+ if (canvasTargets) {
4536
+ var filtered = []; // pick only targets with listeners
4537
+ for (var i = 0; i < canvasTargets.length; i++) {
4538
+ if (canvasTargets[i].listens(type, true)) {
4539
+ filtered.push(canvasTargets[i]);
4540
+ }
4541
+ }
4542
+ targets = filtered.concat(targets);
4543
+ }
4382
4544
 
4383
4545
  if (!targets.length) { return; }
4384
4546
 
4385
- var target = targets[0];
4386
- if (type === 'contextmenu' && target.listens(type, true)) {
4547
+ if (type === 'contextmenu') {
4387
4548
  preventDefault(e);
4388
4549
  }
4389
4550
 
4551
+ var target = targets[0];
4390
4552
  var data = {
4391
4553
  originalEvent: e
4392
4554
  };
@@ -4399,7 +4561,7 @@
4399
4561
  data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);
4400
4562
  }
4401
4563
 
4402
- for (var i = 0; i < targets.length; i++) {
4564
+ for (i = 0; i < targets.length; i++) {
4403
4565
  targets[i].fire(type, data, true);
4404
4566
  if (data.originalEvent._stopped ||
4405
4567
  (targets[i].options.bubblingMouseEvents === false && indexOf(this._mouseEvents, type) !== -1)) { return; }
@@ -4494,7 +4656,7 @@
4494
4656
  // If offset is less than a pixel, ignore.
4495
4657
  // This prevents unstable projections from getting into
4496
4658
  // an infinite loop of tiny offsets.
4497
- if (offset.round().equals([0, 0])) {
4659
+ if (Math.abs(offset.x) <= 1 && Math.abs(offset.y) <= 1) {
4498
4660
  return center;
4499
4661
  }
4500
4662
 
@@ -4535,7 +4697,7 @@
4535
4697
  _limitZoom: function (zoom) {
4536
4698
  var min = this.getMinZoom(),
4537
4699
  max = this.getMaxZoom(),
4538
- snap = any3d ? this.options.zoomSnap : 1;
4700
+ snap = Browser.any3d ? this.options.zoomSnap : 1;
4539
4701
  if (snap) {
4540
4702
  zoom = Math.round(zoom / snap) * snap;
4541
4703
  }
@@ -4626,7 +4788,7 @@
4626
4788
 
4627
4789
  requestAnimFrame(function () {
4628
4790
  this
4629
- ._moveStart(true, false)
4791
+ ._moveStart(true, options.noMoveStart || false)
4630
4792
  ._animateZoom(center, zoom, true);
4631
4793
  }, this);
4632
4794
 
@@ -4655,6 +4817,12 @@
4655
4817
  noUpdate: noUpdate
4656
4818
  });
4657
4819
 
4820
+ if (!this._tempFireZoomEvent) {
4821
+ this._tempFireZoomEvent = this._zoom !== this._animateToZoom;
4822
+ }
4823
+
4824
+ this._move(this._animateToCenter, this._animateToZoom, undefined, true);
4825
+
4658
4826
  // Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693
4659
4827
  setTimeout(bind(this._onZoomTransitionEnd, this), 250);
4660
4828
  },
@@ -4668,12 +4836,16 @@
4668
4836
 
4669
4837
  this._animatingZoom = false;
4670
4838
 
4671
- this._move(this._animateToCenter, this._animateToZoom);
4839
+ this._move(this._animateToCenter, this._animateToZoom, undefined, true);
4672
4840
 
4673
- // This anim frame should prevent an obscure iOS webkit tile loading race condition.
4674
- requestAnimFrame(function () {
4675
- this._moveEnd(true);
4676
- }, this);
4841
+ if (this._tempFireZoomEvent) {
4842
+ this.fire('zoom');
4843
+ }
4844
+ delete this._tempFireZoomEvent;
4845
+
4846
+ this.fire('move');
4847
+
4848
+ this._moveEnd(true);
4677
4849
  }
4678
4850
  });
4679
4851
 
@@ -4702,7 +4874,7 @@
4702
4874
 
4703
4875
  var Control = Class.extend({
4704
4876
  // @section
4705
- // @aka Control options
4877
+ // @aka Control Options
4706
4878
  options: {
4707
4879
  // @option position: String = 'topright'
4708
4880
  // The position of the control (one of the map corners). Possible values are `'topleft'`,
@@ -4865,7 +5037,7 @@
4865
5037
  * @aka L.Control.Layers
4866
5038
  * @inherits Control
4867
5039
  *
4868
- * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](http://leafletjs.com/examples/layers-control/)). Extends `Control`.
5040
+ * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](https://leafletjs.com/examples/layers-control/)). Extends `Control`.
4869
5041
  *
4870
5042
  * @example
4871
5043
  *
@@ -4904,7 +5076,7 @@
4904
5076
  // @aka Control.Layers options
4905
5077
  options: {
4906
5078
  // @option collapsed: Boolean = true
4907
- // If `true`, the control will be collapsed into an icon and expanded on mouse hover or touch.
5079
+ // If `true`, the control will be collapsed into an icon and expanded on mouse hover, touch, or keyboard activation.
4908
5080
  collapsed: true,
4909
5081
  position: 'topright',
4910
5082
 
@@ -4939,6 +5111,7 @@
4939
5111
  this._layers = [];
4940
5112
  this._lastZIndex = 0;
4941
5113
  this._handlingClick = false;
5114
+ this._preventClick = false;
4942
5115
 
4943
5116
  for (var i in baseLayers) {
4944
5117
  this._addLayer(baseLayers[i], i);
@@ -5042,24 +5215,29 @@
5042
5215
  if (collapsed) {
5043
5216
  this._map.on('click', this.collapse, this);
5044
5217
 
5045
- if (!android) {
5046
- on(container, {
5047
- mouseenter: this.expand,
5048
- mouseleave: this.collapse
5049
- }, this);
5050
- }
5218
+ on(container, {
5219
+ mouseenter: this._expandSafely,
5220
+ mouseleave: this.collapse
5221
+ }, this);
5051
5222
  }
5052
5223
 
5053
5224
  var link = this._layersLink = create$1('a', className + '-toggle', container);
5054
5225
  link.href = '#';
5055
5226
  link.title = 'Layers';
5227
+ link.setAttribute('role', 'button');
5056
5228
 
5057
- if (touch) {
5058
- on(link, 'click', stop);
5059
- on(link, 'click', this.expand, this);
5060
- } else {
5061
- on(link, 'focus', this.expand, this);
5062
- }
5229
+ on(link, {
5230
+ keydown: function (e) {
5231
+ if (e.keyCode === 13) {
5232
+ this._expandSafely();
5233
+ }
5234
+ },
5235
+ // Certain screen readers intercept the key event and instead send a click event
5236
+ click: function (e) {
5237
+ preventDefault(e);
5238
+ this._expandSafely();
5239
+ }
5240
+ }, this);
5063
5241
 
5064
5242
  if (!collapsed) {
5065
5243
  this.expand();
@@ -5159,7 +5337,7 @@
5159
5337
  }
5160
5338
  },
5161
5339
 
5162
- // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
5340
+ // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see https://stackoverflow.com/a/119079)
5163
5341
  _createRadioElement: function (name, checked) {
5164
5342
 
5165
5343
  var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' +
@@ -5195,7 +5373,7 @@
5195
5373
 
5196
5374
  // Helps from preventing layer control flicker when checkboxes are disabled
5197
5375
  // https://github.com/Leaflet/Leaflet/issues/2771
5198
- var holder = document.createElement('div');
5376
+ var holder = document.createElement('span');
5199
5377
 
5200
5378
  label.appendChild(holder);
5201
5379
  holder.appendChild(input);
@@ -5209,6 +5387,11 @@
5209
5387
  },
5210
5388
 
5211
5389
  _onInputClick: function () {
5390
+ // expanding the control on mobile with a click can cause adding a layer - we don't want this
5391
+ if (this._preventClick) {
5392
+ return;
5393
+ }
5394
+
5212
5395
  var inputs = this._layerControlInputs,
5213
5396
  input, layer;
5214
5397
  var addedLayers = [],
@@ -5266,14 +5449,16 @@
5266
5449
  return this;
5267
5450
  },
5268
5451
 
5269
- _expand: function () {
5270
- // Backward compatibility, remove me in 1.1.
5271
- return this.expand();
5272
- },
5273
-
5274
- _collapse: function () {
5275
- // Backward compatibility, remove me in 1.1.
5276
- return this.collapse();
5452
+ _expandSafely: function () {
5453
+ var section = this._section;
5454
+ this._preventClick = true;
5455
+ on(section, 'click', preventDefault);
5456
+ this.expand();
5457
+ var that = this;
5458
+ setTimeout(function () {
5459
+ off(section, 'click', preventDefault);
5460
+ that._preventClick = false;
5461
+ });
5277
5462
  }
5278
5463
 
5279
5464
  });
@@ -5299,17 +5484,17 @@
5299
5484
  options: {
5300
5485
  position: 'topleft',
5301
5486
 
5302
- // @option zoomInText: String = '+'
5487
+ // @option zoomInText: String = '<span aria-hidden="true">+</span>'
5303
5488
  // The text set on the 'zoom in' button.
5304
- zoomInText: '+',
5489
+ zoomInText: '<span aria-hidden="true">+</span>',
5305
5490
 
5306
5491
  // @option zoomInTitle: String = 'Zoom in'
5307
5492
  // The title set on the 'zoom in' button.
5308
5493
  zoomInTitle: 'Zoom in',
5309
5494
 
5310
- // @option zoomOutText: String = '&#x2212;'
5495
+ // @option zoomOutText: String = '<span aria-hidden="true">&#x2212;</span>'
5311
5496
  // The text set on the 'zoom out' button.
5312
- zoomOutText: '&#x2212;',
5497
+ zoomOutText: '<span aria-hidden="true">&#x2212;</span>',
5313
5498
 
5314
5499
  // @option zoomOutTitle: String = 'Zoom out'
5315
5500
  // The title set on the 'zoom out' button.
@@ -5386,12 +5571,16 @@
5386
5571
 
5387
5572
  removeClass(this._zoomInButton, className);
5388
5573
  removeClass(this._zoomOutButton, className);
5574
+ this._zoomInButton.setAttribute('aria-disabled', 'false');
5575
+ this._zoomOutButton.setAttribute('aria-disabled', 'false');
5389
5576
 
5390
5577
  if (this._disabled || map._zoom === map.getMinZoom()) {
5391
5578
  addClass(this._zoomOutButton, className);
5579
+ this._zoomOutButton.setAttribute('aria-disabled', 'true');
5392
5580
  }
5393
5581
  if (this._disabled || map._zoom === map.getMaxZoom()) {
5394
5582
  addClass(this._zoomInButton, className);
5583
+ this._zoomInButton.setAttribute('aria-disabled', 'true');
5395
5584
  }
5396
5585
  }
5397
5586
  });
@@ -5551,6 +5740,9 @@
5551
5740
  return new Scale(options);
5552
5741
  };
5553
5742
 
5743
+ var ukrainianFlag = '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="12" height="8" viewBox="0 0 12 8" class="leaflet-attribution-flag"><path fill="#4C7BE1" d="M0 0h12v4H0z"/><path fill="#FFD500" d="M0 4h12v3H0z"/><path fill="#E0BC00" d="M0 7h12v1H0z"/></svg>';
5744
+
5745
+
5554
5746
  /*
5555
5747
  * @class Control.Attribution
5556
5748
  * @aka L.Control.Attribution
@@ -5565,9 +5757,9 @@
5565
5757
  options: {
5566
5758
  position: 'bottomright',
5567
5759
 
5568
- // @option prefix: String = 'Leaflet'
5760
+ // @option prefix: String|false = 'Leaflet'
5569
5761
  // The HTML text shown before the attributions. Pass `false` to disable.
5570
- prefix: '<a href="https://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'
5762
+ prefix: '<a href="https://leafletjs.com" title="A JavaScript library for interactive maps">' + (Browser.inlineSvg ? ukrainianFlag + ' ' : '') + 'Leaflet</a>'
5571
5763
  },
5572
5764
 
5573
5765
  initialize: function (options) {
@@ -5590,11 +5782,26 @@
5590
5782
 
5591
5783
  this._update();
5592
5784
 
5785
+ map.on('layeradd', this._addAttribution, this);
5786
+
5593
5787
  return this._container;
5594
5788
  },
5595
5789
 
5596
- // @method setPrefix(prefix: String): this
5597
- // Sets the text before the attributions.
5790
+ onRemove: function (map) {
5791
+ map.off('layeradd', this._addAttribution, this);
5792
+ },
5793
+
5794
+ _addAttribution: function (ev) {
5795
+ if (ev.layer.getAttribution) {
5796
+ this.addAttribution(ev.layer.getAttribution());
5797
+ ev.layer.once('remove', function () {
5798
+ this.removeAttribution(ev.layer.getAttribution());
5799
+ }, this);
5800
+ }
5801
+ },
5802
+
5803
+ // @method setPrefix(prefix: String|false): this
5804
+ // The HTML text shown before the attributions. Pass `false` to disable.
5598
5805
  setPrefix: function (prefix) {
5599
5806
  this.options.prefix = prefix;
5600
5807
  this._update();
@@ -5602,7 +5809,7 @@
5602
5809
  },
5603
5810
 
5604
5811
  // @method addAttribution(text: String): this
5605
- // Adds an attribution text (e.g. `'Vector data &copy; Mapbox'`).
5812
+ // Adds an attribution text (e.g. `'&copy; OpenStreetMap contributors'`).
5606
5813
  addAttribution: function (text) {
5607
5814
  if (!text) { return this; }
5608
5815
 
@@ -5649,7 +5856,7 @@
5649
5856
  prefixAndAttribs.push(attribs.join(', '));
5650
5857
  }
5651
5858
 
5652
- this._container.innerHTML = prefixAndAttribs.join(' | ');
5859
+ this._container.innerHTML = prefixAndAttribs.join(' <span aria-hidden="true">|</span> ');
5653
5860
  }
5654
5861
  });
5655
5862
 
@@ -5758,20 +5965,7 @@
5758
5965
  * ```
5759
5966
  */
5760
5967
 
5761
- var START = touch ? 'touchstart mousedown' : 'mousedown';
5762
- var END = {
5763
- mousedown: 'mouseup',
5764
- touchstart: 'touchend',
5765
- pointerdown: 'touchend',
5766
- MSPointerDown: 'touchend'
5767
- };
5768
- var MOVE = {
5769
- mousedown: 'mousemove',
5770
- touchstart: 'touchmove',
5771
- pointerdown: 'touchmove',
5772
- MSPointerDown: 'touchmove'
5773
- };
5774
-
5968
+ var START = Browser.touch ? 'touchstart mousedown' : 'mousedown';
5775
5969
 
5776
5970
  var Draggable = Evented.extend({
5777
5971
 
@@ -5786,12 +5980,12 @@
5786
5980
 
5787
5981
  // @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options)
5788
5982
  // Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).
5789
- initialize: function (element, dragStartTarget, preventOutline$$1, options) {
5983
+ initialize: function (element, dragStartTarget, preventOutline, options) {
5790
5984
  setOptions(this, options);
5791
5985
 
5792
5986
  this._element = element;
5793
5987
  this._dragStartTarget = dragStartTarget || element;
5794
- this._preventOutline = preventOutline$$1;
5988
+ this._preventOutline = preventOutline;
5795
5989
  },
5796
5990
 
5797
5991
  // @method enable()
@@ -5812,7 +6006,7 @@
5812
6006
  // If we're currently dragging this draggable,
5813
6007
  // disabling it counts as first ending the drag.
5814
6008
  if (Draggable._dragging === this) {
5815
- this.finishDrag();
6009
+ this.finishDrag(true);
5816
6010
  }
5817
6011
 
5818
6012
  off(this._dragStartTarget, START, this._onDown, this);
@@ -5822,17 +6016,22 @@
5822
6016
  },
5823
6017
 
5824
6018
  _onDown: function (e) {
5825
- // Ignore simulated events, since we handle both touch and
5826
- // mouse explicitly; otherwise we risk getting duplicates of
5827
- // touch events, see #4315.
5828
- // Also ignore the event if disabled; this happens in IE11
6019
+ // Ignore the event if disabled; this happens in IE11
5829
6020
  // under some circumstances, see #3666.
5830
- if (e._simulated || !this._enabled) { return; }
6021
+ if (!this._enabled) { return; }
5831
6022
 
5832
6023
  this._moved = false;
5833
6024
 
5834
6025
  if (hasClass(this._element, 'leaflet-zoom-anim')) { return; }
5835
6026
 
6027
+ if (e.touches && e.touches.length !== 1) {
6028
+ // Finish dragging to avoid conflict with touchZoom
6029
+ if (Draggable._dragging === this) {
6030
+ this.finishDrag();
6031
+ }
6032
+ return;
6033
+ }
6034
+
5836
6035
  if (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
5837
6036
  Draggable._dragging = this; // Prevent dragging multiple objects at once.
5838
6037
 
@@ -5853,21 +6052,20 @@
5853
6052
  sizedParent = getSizedParentNode(this._element);
5854
6053
 
5855
6054
  this._startPoint = new Point(first.clientX, first.clientY);
6055
+ this._startPos = getPosition(this._element);
5856
6056
 
5857
6057
  // Cache the scale, so that we can continuously compensate for it during drag (_onMove).
5858
6058
  this._parentScale = getScale(sizedParent);
5859
6059
 
5860
- on(document, MOVE[e.type], this._onMove, this);
5861
- on(document, END[e.type], this._onUp, this);
6060
+ var mouseevent = e.type === 'mousedown';
6061
+ on(document, mouseevent ? 'mousemove' : 'touchmove', this._onMove, this);
6062
+ on(document, mouseevent ? 'mouseup' : 'touchend touchcancel', this._onUp, this);
5862
6063
  },
5863
6064
 
5864
6065
  _onMove: function (e) {
5865
- // Ignore simulated events, since we handle both touch and
5866
- // mouse explicitly; otherwise we risk getting duplicates of
5867
- // touch events, see #4315.
5868
- // Also ignore the event if disabled; this happens in IE11
6066
+ // Ignore the event if disabled; this happens in IE11
5869
6067
  // under some circumstances, see #3666.
5870
- if (e._simulated || !this._enabled) { return; }
6068
+ if (!this._enabled) { return; }
5871
6069
 
5872
6070
  if (e.touches && e.touches.length > 1) {
5873
6071
  this._moved = true;
@@ -5894,7 +6092,6 @@
5894
6092
  this.fire('dragstart');
5895
6093
 
5896
6094
  this._moved = true;
5897
- this._startPos = getPosition(this._element).subtract(offset);
5898
6095
 
5899
6096
  addClass(document.body, 'leaflet-dragging');
5900
6097
 
@@ -5910,9 +6107,8 @@
5910
6107
  this._newPos = this._startPos.add(offset);
5911
6108
  this._moving = true;
5912
6109
 
5913
- cancelAnimFrame(this._animRequest);
5914
6110
  this._lastEvent = e;
5915
- this._animRequest = requestAnimFrame(this._updatePosition, this, true);
6111
+ this._updatePosition();
5916
6112
  },
5917
6113
 
5918
6114
  _updatePosition: function () {
@@ -5929,17 +6125,14 @@
5929
6125
  this.fire('drag', e);
5930
6126
  },
5931
6127
 
5932
- _onUp: function (e) {
5933
- // Ignore simulated events, since we handle both touch and
5934
- // mouse explicitly; otherwise we risk getting duplicates of
5935
- // touch events, see #4315.
5936
- // Also ignore the event if disabled; this happens in IE11
6128
+ _onUp: function () {
6129
+ // Ignore the event if disabled; this happens in IE11
5937
6130
  // under some circumstances, see #3666.
5938
- if (e._simulated || !this._enabled) { return; }
6131
+ if (!this._enabled) { return; }
5939
6132
  this.finishDrag();
5940
6133
  },
5941
6134
 
5942
- finishDrag: function () {
6135
+ finishDrag: function (noInertia) {
5943
6136
  removeClass(document.body, 'leaflet-dragging');
5944
6137
 
5945
6138
  if (this._lastTarget) {
@@ -5947,31 +6140,162 @@
5947
6140
  this._lastTarget = null;
5948
6141
  }
5949
6142
 
5950
- for (var i in MOVE) {
5951
- off(document, MOVE[i], this._onMove, this);
5952
- off(document, END[i], this._onUp, this);
5953
- }
6143
+ off(document, 'mousemove touchmove', this._onMove, this);
6144
+ off(document, 'mouseup touchend touchcancel', this._onUp, this);
5954
6145
 
5955
6146
  enableImageDrag();
5956
6147
  enableTextSelection();
5957
6148
 
5958
- if (this._moved && this._moving) {
5959
- // ensure drag is not fired after dragend
5960
- cancelAnimFrame(this._animRequest);
6149
+ var fireDragend = this._moved && this._moving;
5961
6150
 
6151
+ this._moving = false;
6152
+ Draggable._dragging = false;
6153
+
6154
+ if (fireDragend) {
5962
6155
  // @event dragend: DragEndEvent
5963
6156
  // Fired when the drag ends.
5964
6157
  this.fire('dragend', {
6158
+ noInertia: noInertia,
5965
6159
  distance: this._newPos.distanceTo(this._startPos)
5966
6160
  });
5967
6161
  }
5968
-
5969
- this._moving = false;
5970
- Draggable._dragging = false;
5971
6162
  }
5972
6163
 
5973
6164
  });
5974
6165
 
6166
+ /*
6167
+ * @namespace PolyUtil
6168
+ * Various utility functions for polygon geometries.
6169
+ */
6170
+
6171
+ /* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
6172
+ * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
6173
+ * Used by Leaflet to only show polygon points that are on the screen or near, increasing
6174
+ * performance. Note that polygon points needs different algorithm for clipping
6175
+ * than polyline, so there's a separate method for it.
6176
+ */
6177
+ function clipPolygon(points, bounds, round) {
6178
+ var clippedPoints,
6179
+ edges = [1, 4, 2, 8],
6180
+ i, j, k,
6181
+ a, b,
6182
+ len, edge, p;
6183
+
6184
+ for (i = 0, len = points.length; i < len; i++) {
6185
+ points[i]._code = _getBitCode(points[i], bounds);
6186
+ }
6187
+
6188
+ // for each edge (left, bottom, right, top)
6189
+ for (k = 0; k < 4; k++) {
6190
+ edge = edges[k];
6191
+ clippedPoints = [];
6192
+
6193
+ for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
6194
+ a = points[i];
6195
+ b = points[j];
6196
+
6197
+ // if a is inside the clip window
6198
+ if (!(a._code & edge)) {
6199
+ // if b is outside the clip window (a->b goes out of screen)
6200
+ if (b._code & edge) {
6201
+ p = _getEdgeIntersection(b, a, edge, bounds, round);
6202
+ p._code = _getBitCode(p, bounds);
6203
+ clippedPoints.push(p);
6204
+ }
6205
+ clippedPoints.push(a);
6206
+
6207
+ // else if b is inside the clip window (a->b enters the screen)
6208
+ } else if (!(b._code & edge)) {
6209
+ p = _getEdgeIntersection(b, a, edge, bounds, round);
6210
+ p._code = _getBitCode(p, bounds);
6211
+ clippedPoints.push(p);
6212
+ }
6213
+ }
6214
+ points = clippedPoints;
6215
+ }
6216
+
6217
+ return points;
6218
+ }
6219
+
6220
+ /* @function polygonCenter(latlngs: LatLng[], crs: CRS): LatLng
6221
+ * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polygon.
6222
+ */
6223
+ function polygonCenter(latlngs, crs) {
6224
+ var i, j, p1, p2, f, area, x, y, center;
6225
+
6226
+ if (!latlngs || latlngs.length === 0) {
6227
+ throw new Error('latlngs not passed');
6228
+ }
6229
+
6230
+ if (!isFlat(latlngs)) {
6231
+ console.warn('latlngs are not flat! Only the first ring will be used');
6232
+ latlngs = latlngs[0];
6233
+ }
6234
+
6235
+ var centroidLatLng = toLatLng([0, 0]);
6236
+
6237
+ var bounds = toLatLngBounds(latlngs);
6238
+ var areaBounds = bounds.getNorthWest().distanceTo(bounds.getSouthWest()) * bounds.getNorthEast().distanceTo(bounds.getNorthWest());
6239
+ // tests showed that below 1700 rounding errors are happening
6240
+ if (areaBounds < 1700) {
6241
+ // getting a inexact center, to move the latlngs near to [0, 0] to prevent rounding errors
6242
+ centroidLatLng = centroid(latlngs);
6243
+ }
6244
+
6245
+ var len = latlngs.length;
6246
+ var points = [];
6247
+ for (i = 0; i < len; i++) {
6248
+ var latlng = toLatLng(latlngs[i]);
6249
+ points.push(crs.project(toLatLng([latlng.lat - centroidLatLng.lat, latlng.lng - centroidLatLng.lng])));
6250
+ }
6251
+
6252
+ area = x = y = 0;
6253
+
6254
+ // polygon centroid algorithm;
6255
+ for (i = 0, j = len - 1; i < len; j = i++) {
6256
+ p1 = points[i];
6257
+ p2 = points[j];
6258
+
6259
+ f = p1.y * p2.x - p2.y * p1.x;
6260
+ x += (p1.x + p2.x) * f;
6261
+ y += (p1.y + p2.y) * f;
6262
+ area += f * 3;
6263
+ }
6264
+
6265
+ if (area === 0) {
6266
+ // Polygon is so small that all points are on same pixel.
6267
+ center = points[0];
6268
+ } else {
6269
+ center = [x / area, y / area];
6270
+ }
6271
+
6272
+ var latlngCenter = crs.unproject(toPoint(center));
6273
+ return toLatLng([latlngCenter.lat + centroidLatLng.lat, latlngCenter.lng + centroidLatLng.lng]);
6274
+ }
6275
+
6276
+ /* @function centroid(latlngs: LatLng[]): LatLng
6277
+ * Returns the 'center of mass' of the passed LatLngs.
6278
+ */
6279
+ function centroid(coords) {
6280
+ var latSum = 0;
6281
+ var lngSum = 0;
6282
+ var len = 0;
6283
+ for (var i = 0; i < coords.length; i++) {
6284
+ var latlng = toLatLng(coords[i]);
6285
+ latSum += latlng.lat;
6286
+ lngSum += latlng.lng;
6287
+ len++;
6288
+ }
6289
+ return toLatLng([latSum / len, lngSum / len]);
6290
+ }
6291
+
6292
+ var PolyUtil = {
6293
+ __proto__: null,
6294
+ clipPolygon: clipPolygon,
6295
+ polygonCenter: polygonCenter,
6296
+ centroid: centroid
6297
+ };
6298
+
5975
6299
  /*
5976
6300
  * @namespace LineUtil
5977
6301
  *
@@ -5984,11 +6308,11 @@
5984
6308
  // @function simplify(points: Point[], tolerance: Number): Point[]
5985
6309
  // Dramatically reduces the number of points in a polyline while retaining
5986
6310
  // its shape and returns a new array of simplified points, using the
5987
- // [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm).
6311
+ // [Ramer-Douglas-Peucker algorithm](https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm).
5988
6312
  // Used for a huge performance boost when processing/displaying Leaflet polylines for
5989
6313
  // each zoom level and also reducing visual noise. tolerance affects the amount of
5990
6314
  // simplification (lesser value means higher quality but slower and with more points).
5991
- // Also released as a separated micro-library [Simplify.js](http://mourner.github.com/simplify-js/).
6315
+ // Also released as a separated micro-library [Simplify.js](https://mourner.github.io/simplify-js/).
5992
6316
  function simplify(points, tolerance) {
5993
6317
  if (!tolerance || !points.length) {
5994
6318
  return points.slice();
@@ -6017,7 +6341,7 @@
6017
6341
  return _sqClosestPointOnSegment(p, p1, p2);
6018
6342
  }
6019
6343
 
6020
- // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm
6344
+ // Ramer-Douglas-Peucker simplification, see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
6021
6345
  function _simplifyDP(points, sqTolerance) {
6022
6346
 
6023
6347
  var len = points.length,
@@ -6209,77 +6533,82 @@
6209
6533
  function _flat(latlngs) {
6210
6534
  console.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.');
6211
6535
  return isFlat(latlngs);
6212
- }
6213
-
6214
- var LineUtil = ({
6215
- simplify: simplify,
6216
- pointToSegmentDistance: pointToSegmentDistance,
6217
- closestPointOnSegment: closestPointOnSegment,
6218
- clipSegment: clipSegment,
6219
- _getEdgeIntersection: _getEdgeIntersection,
6220
- _getBitCode: _getBitCode,
6221
- _sqClosestPointOnSegment: _sqClosestPointOnSegment,
6222
- isFlat: isFlat,
6223
- _flat: _flat
6224
- });
6225
-
6226
- /*
6227
- * @namespace PolyUtil
6228
- * Various utility functions for polygon geometries.
6229
- */
6230
-
6231
- /* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
6232
- * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
6233
- * Used by Leaflet to only show polygon points that are on the screen or near, increasing
6234
- * performance. Note that polygon points needs different algorithm for clipping
6235
- * than polyline, so there's a separate method for it.
6236
- */
6237
- function clipPolygon(points, bounds, round) {
6238
- var clippedPoints,
6239
- edges = [1, 4, 2, 8],
6240
- i, j, k,
6241
- a, b,
6242
- len, edge, p;
6536
+ }
6243
6537
 
6244
- for (i = 0, len = points.length; i < len; i++) {
6245
- points[i]._code = _getBitCode(points[i], bounds);
6538
+ /* @function polylineCenter(latlngs: LatLng[], crs: CRS): LatLng
6539
+ * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polyline.
6540
+ */
6541
+ function polylineCenter(latlngs, crs) {
6542
+ var i, halfDist, segDist, dist, p1, p2, ratio, center;
6543
+
6544
+ if (!latlngs || latlngs.length === 0) {
6545
+ throw new Error('latlngs not passed');
6246
6546
  }
6247
6547
 
6248
- // for each edge (left, bottom, right, top)
6249
- for (k = 0; k < 4; k++) {
6250
- edge = edges[k];
6251
- clippedPoints = [];
6548
+ if (!isFlat(latlngs)) {
6549
+ console.warn('latlngs are not flat! Only the first ring will be used');
6550
+ latlngs = latlngs[0];
6551
+ }
6252
6552
 
6253
- for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
6254
- a = points[i];
6255
- b = points[j];
6553
+ var centroidLatLng = toLatLng([0, 0]);
6256
6554
 
6257
- // if a is inside the clip window
6258
- if (!(a._code & edge)) {
6259
- // if b is outside the clip window (a->b goes out of screen)
6260
- if (b._code & edge) {
6261
- p = _getEdgeIntersection(b, a, edge, bounds, round);
6262
- p._code = _getBitCode(p, bounds);
6263
- clippedPoints.push(p);
6264
- }
6265
- clippedPoints.push(a);
6555
+ var bounds = toLatLngBounds(latlngs);
6556
+ var areaBounds = bounds.getNorthWest().distanceTo(bounds.getSouthWest()) * bounds.getNorthEast().distanceTo(bounds.getNorthWest());
6557
+ // tests showed that below 1700 rounding errors are happening
6558
+ if (areaBounds < 1700) {
6559
+ // getting a inexact center, to move the latlngs near to [0, 0] to prevent rounding errors
6560
+ centroidLatLng = centroid(latlngs);
6561
+ }
6266
6562
 
6267
- // else if b is inside the clip window (a->b enters the screen)
6268
- } else if (!(b._code & edge)) {
6269
- p = _getEdgeIntersection(b, a, edge, bounds, round);
6270
- p._code = _getBitCode(p, bounds);
6271
- clippedPoints.push(p);
6563
+ var len = latlngs.length;
6564
+ var points = [];
6565
+ for (i = 0; i < len; i++) {
6566
+ var latlng = toLatLng(latlngs[i]);
6567
+ points.push(crs.project(toLatLng([latlng.lat - centroidLatLng.lat, latlng.lng - centroidLatLng.lng])));
6568
+ }
6569
+
6570
+ for (i = 0, halfDist = 0; i < len - 1; i++) {
6571
+ halfDist += points[i].distanceTo(points[i + 1]) / 2;
6572
+ }
6573
+
6574
+ // The line is so small in the current view that all points are on the same pixel.
6575
+ if (halfDist === 0) {
6576
+ center = points[0];
6577
+ } else {
6578
+ for (i = 0, dist = 0; i < len - 1; i++) {
6579
+ p1 = points[i];
6580
+ p2 = points[i + 1];
6581
+ segDist = p1.distanceTo(p2);
6582
+ dist += segDist;
6583
+
6584
+ if (dist > halfDist) {
6585
+ ratio = (dist - halfDist) / segDist;
6586
+ center = [
6587
+ p2.x - ratio * (p2.x - p1.x),
6588
+ p2.y - ratio * (p2.y - p1.y)
6589
+ ];
6590
+ break;
6272
6591
  }
6273
6592
  }
6274
- points = clippedPoints;
6275
6593
  }
6276
6594
 
6277
- return points;
6595
+ var latlngCenter = crs.unproject(toPoint(center));
6596
+ return toLatLng([latlngCenter.lat + centroidLatLng.lat, latlngCenter.lng + centroidLatLng.lng]);
6278
6597
  }
6279
6598
 
6280
- var PolyUtil = ({
6281
- clipPolygon: clipPolygon
6282
- });
6599
+ var LineUtil = {
6600
+ __proto__: null,
6601
+ simplify: simplify,
6602
+ pointToSegmentDistance: pointToSegmentDistance,
6603
+ closestPointOnSegment: closestPointOnSegment,
6604
+ clipSegment: clipSegment,
6605
+ _getEdgeIntersection: _getEdgeIntersection,
6606
+ _getBitCode: _getBitCode,
6607
+ _sqClosestPointOnSegment: _sqClosestPointOnSegment,
6608
+ isFlat: isFlat,
6609
+ _flat: _flat,
6610
+ polylineCenter: polylineCenter
6611
+ };
6283
6612
 
6284
6613
  /*
6285
6614
  * @namespace Projection
@@ -6356,7 +6685,7 @@
6356
6685
  * @class Projection
6357
6686
 
6358
6687
  * An object with methods for projecting geographical coordinates of the world onto
6359
- * a flat surface (and back). See [Map projection](http://en.wikipedia.org/wiki/Map_projection).
6688
+ * a flat surface (and back). See [Map projection](https://en.wikipedia.org/wiki/Map_projection).
6360
6689
 
6361
6690
  * @property bounds: Bounds
6362
6691
  * The bounds (specified in CRS units) where the projection is valid
@@ -6375,11 +6704,12 @@
6375
6704
 
6376
6705
  */
6377
6706
 
6378
- var index = ({
6707
+ var index = {
6708
+ __proto__: null,
6379
6709
  LonLat: LonLat,
6380
6710
  Mercator: Mercator,
6381
6711
  SphericalMercator: SphericalMercator
6382
- });
6712
+ };
6383
6713
 
6384
6714
  /*
6385
6715
  * @namespace CRS
@@ -6566,10 +6896,6 @@
6566
6896
 
6567
6897
  this.onAdd(map);
6568
6898
 
6569
- if (this.getAttribution && map.attributionControl) {
6570
- map.attributionControl.addAttribution(this.getAttribution());
6571
- }
6572
-
6573
6899
  this.fire('add');
6574
6900
  map.fire('layeradd', {layer: this});
6575
6901
  }
@@ -6642,10 +6968,6 @@
6642
6968
  layer.onRemove(this);
6643
6969
  }
6644
6970
 
6645
- if (layer.getAttribution && this.attributionControl) {
6646
- this.attributionControl.removeAttribution(layer.getAttribution());
6647
- }
6648
-
6649
6971
  delete this._layers[id];
6650
6972
 
6651
6973
  if (this._loaded) {
@@ -6661,7 +6983,7 @@
6661
6983
  // @method hasLayer(layer: Layer): Boolean
6662
6984
  // Returns `true` if the given layer is currently added to the map
6663
6985
  hasLayer: function (layer) {
6664
- return !!layer && (stamp(layer) in this._layers);
6986
+ return stamp(layer) in this._layers;
6665
6987
  },
6666
6988
 
6667
6989
  /* @method eachLayer(fn: Function, context?: Object): this
@@ -6688,7 +7010,7 @@
6688
7010
  },
6689
7011
 
6690
7012
  _addZoomLimit: function (layer) {
6691
- if (isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {
7013
+ if (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {
6692
7014
  this._zoomBoundLayers[stamp(layer)] = layer;
6693
7015
  this._updateZoomLevels();
6694
7016
  }
@@ -6738,7 +7060,7 @@
6738
7060
  /*
6739
7061
  * @class LayerGroup
6740
7062
  * @aka L.LayerGroup
6741
- * @inherits Layer
7063
+ * @inherits Interactive layer
6742
7064
  *
6743
7065
  * Used to group several layers and handle them as one. If you add it to the map,
6744
7066
  * any layers added or removed from the group will be added/removed on the map as
@@ -6806,7 +7128,6 @@
6806
7128
  // @method hasLayer(id: Number): Boolean
6807
7129
  // Returns `true` if the given internal ID is currently added to the group.
6808
7130
  hasLayer: function (layer) {
6809
- if (!layer) { return false; }
6810
7131
  var layerId = typeof layer === 'number' ? layer : this.getLayerId(layer);
6811
7132
  return layerId in this._layers;
6812
7133
  },
@@ -7056,7 +7377,13 @@
7056
7377
 
7057
7378
  options: {
7058
7379
  popupAnchor: [0, 0],
7059
- tooltipAnchor: [0, 0]
7380
+ tooltipAnchor: [0, 0],
7381
+
7382
+ // @option crossOrigin: Boolean|String = false
7383
+ // Whether the crossOrigin attribute will be added to the tiles.
7384
+ // If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.
7385
+ // Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
7386
+ crossOrigin: false
7060
7387
  },
7061
7388
 
7062
7389
  initialize: function (options) {
@@ -7089,6 +7416,10 @@
7089
7416
  var img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);
7090
7417
  this._setIconStyles(img, name);
7091
7418
 
7419
+ if (this.options.crossOrigin || this.options.crossOrigin === '') {
7420
+ img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
7421
+ }
7422
+
7092
7423
  return img;
7093
7424
  },
7094
7425
 
@@ -7124,7 +7455,7 @@
7124
7455
  },
7125
7456
 
7126
7457
  _getIconUrl: function (name) {
7127
- return retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];
7458
+ return Browser.retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];
7128
7459
  }
7129
7460
  });
7130
7461
 
@@ -7165,7 +7496,7 @@
7165
7496
  },
7166
7497
 
7167
7498
  _getIconUrl: function (name) {
7168
- if (!IconDefault.imagePath) { // Deprecated, backwards-compatibility only
7499
+ if (typeof IconDefault.imagePath !== 'string') { // Deprecated, backwards-compatibility only
7169
7500
  IconDefault.imagePath = this._detectIconPath();
7170
7501
  }
7171
7502
 
@@ -7176,20 +7507,26 @@
7176
7507
  return (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);
7177
7508
  },
7178
7509
 
7510
+ _stripUrl: function (path) { // separate function to use in tests
7511
+ var strip = function (str, re, idx) {
7512
+ var match = re.exec(str);
7513
+ return match && match[idx];
7514
+ };
7515
+ path = strip(path, /^url\((['"])?(.+)\1\)$/, 2);
7516
+ return path && strip(path, /^(.*)marker-icon\.png$/, 1);
7517
+ },
7518
+
7179
7519
  _detectIconPath: function () {
7180
7520
  var el = create$1('div', 'leaflet-default-icon-path', document.body);
7181
7521
  var path = getStyle(el, 'background-image') ||
7182
7522
  getStyle(el, 'backgroundImage'); // IE8
7183
7523
 
7184
7524
  document.body.removeChild(el);
7185
-
7186
- if (path === null || path.indexOf('url') !== 0) {
7187
- path = '';
7188
- } else {
7189
- path = path.replace(/^url\(["']?/, '').replace(/marker-icon\.png["']?\)$/, '');
7190
- }
7191
-
7192
- return path;
7525
+ path = this._stripUrl(path);
7526
+ if (path) { return path; }
7527
+ var link = document.querySelector('link[href$="leaflet.css"]');
7528
+ if (!link) { return ''; }
7529
+ return link.href.substring(0, link.href.length - 'leaflet.css'.length - 1);
7193
7530
  }
7194
7531
  });
7195
7532
 
@@ -7381,11 +7718,13 @@
7381
7718
 
7382
7719
  // @option title: String = ''
7383
7720
  // Text for the browser tooltip that appear on marker hover (no tooltip by default).
7721
+ // [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled).
7384
7722
  title: '',
7385
7723
 
7386
- // @option alt: String = ''
7387
- // Text for the `alt` attribute of the icon image (useful for accessibility).
7388
- alt: '',
7724
+ // @option alt: String = 'Marker'
7725
+ // Text for the `alt` attribute of the icon image.
7726
+ // [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled).
7727
+ alt: 'Marker',
7389
7728
 
7390
7729
  // @option zIndexOffset: Number = 0
7391
7730
  // By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like `1000` (or high negative value, respectively).
@@ -7416,6 +7755,12 @@
7416
7755
  // (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
7417
7756
  bubblingMouseEvents: false,
7418
7757
 
7758
+ // @option autoPanOnFocus: Boolean = true
7759
+ // When `true`, the map will pan whenever the marker is focused (via
7760
+ // e.g. pressing `tab` on the keyboard) to ensure the marker is
7761
+ // visible within the map's bounds
7762
+ autoPanOnFocus: true,
7763
+
7419
7764
  // @section Draggable marker options
7420
7765
  // @option draggable: Boolean = false
7421
7766
  // Whether the marker is draggable with mouse/touch or not.
@@ -7568,6 +7913,7 @@
7568
7913
 
7569
7914
  if (options.keyboard) {
7570
7915
  icon.tabIndex = '0';
7916
+ icon.setAttribute('role', 'button');
7571
7917
  }
7572
7918
 
7573
7919
  this._icon = icon;
@@ -7579,6 +7925,10 @@
7579
7925
  });
7580
7926
  }
7581
7927
 
7928
+ if (this.options.autoPanOnFocus) {
7929
+ on(icon, 'focus', this._panOnFocus, this);
7930
+ }
7931
+
7582
7932
  var newShadow = options.icon.createShadow(this._shadow),
7583
7933
  addShadow = false;
7584
7934
 
@@ -7616,6 +7966,10 @@
7616
7966
  });
7617
7967
  }
7618
7968
 
7969
+ if (this.options.autoPanOnFocus) {
7970
+ off(this._icon, 'focus', this._panOnFocus, this);
7971
+ }
7972
+
7619
7973
  remove(this._icon);
7620
7974
  this.removeInteractiveTarget(this._icon);
7621
7975
 
@@ -7710,6 +8064,20 @@
7710
8064
  this._updateZIndex(0);
7711
8065
  },
7712
8066
 
8067
+ _panOnFocus: function () {
8068
+ var map = this._map;
8069
+ if (!map) { return; }
8070
+
8071
+ var iconOpts = this.options.icon.options;
8072
+ var size = iconOpts.iconSize ? toPoint(iconOpts.iconSize) : toPoint(0, 0);
8073
+ var anchor = iconOpts.iconAnchor ? toPoint(iconOpts.iconAnchor) : toPoint(0, 0);
8074
+
8075
+ map.panInside(this._latlng, {
8076
+ paddingTopLeft: anchor,
8077
+ paddingBottomRight: size.subtract(anchor)
8078
+ });
8079
+ },
8080
+
7713
8081
  _getPopupAnchor: function () {
7714
8082
  return this.options.icon.options.popupAnchor;
7715
8083
  },
@@ -7869,7 +8237,8 @@
7869
8237
 
7870
8238
  _clickTolerance: function () {
7871
8239
  // used when doing hit detection for Canvas layers
7872
- return (this.options.stroke ? this.options.weight / 2 : 0) + this._renderer.options.tolerance;
8240
+ return (this.options.stroke ? this.options.weight / 2 : 0) +
8241
+ (this._renderer.options.tolerance || 0);
7873
8242
  }
7874
8243
  });
7875
8244
 
@@ -8191,44 +8560,13 @@
8191
8560
  },
8192
8561
 
8193
8562
  // @method getCenter(): LatLng
8194
- // Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the polyline.
8563
+ // Returns the center ([centroid](https://en.wikipedia.org/wiki/Centroid)) of the polyline.
8195
8564
  getCenter: function () {
8196
8565
  // throws error when not yet added to map as this center calculation requires projected coordinates
8197
8566
  if (!this._map) {
8198
8567
  throw new Error('Must add layer to map before using getCenter()');
8199
8568
  }
8200
-
8201
- var i, halfDist, segDist, dist, p1, p2, ratio,
8202
- points = this._rings[0],
8203
- len = points.length;
8204
-
8205
- if (!len) { return null; }
8206
-
8207
- // polyline centroid algorithm; only uses the first ring if there are multiple
8208
-
8209
- for (i = 0, halfDist = 0; i < len - 1; i++) {
8210
- halfDist += points[i].distanceTo(points[i + 1]) / 2;
8211
- }
8212
-
8213
- // The line is so small in the current view that all points are on the same pixel.
8214
- if (halfDist === 0) {
8215
- return this._map.layerPointToLatLng(points[0]);
8216
- }
8217
-
8218
- for (i = 0, dist = 0; i < len - 1; i++) {
8219
- p1 = points[i];
8220
- p2 = points[i + 1];
8221
- segDist = p1.distanceTo(p2);
8222
- dist += segDist;
8223
-
8224
- if (dist > halfDist) {
8225
- ratio = (dist - halfDist) / segDist;
8226
- return this._map.layerPointToLatLng([
8227
- p2.x - ratio * (p2.x - p1.x),
8228
- p2.y - ratio * (p2.y - p1.y)
8229
- ]);
8230
- }
8231
- }
8569
+ return polylineCenter(this._defaultShape(), this._map.options.crs);
8232
8570
  },
8233
8571
 
8234
8572
  // @method getBounds(): LatLngBounds
@@ -8289,6 +8627,11 @@
8289
8627
  _updateBounds: function () {
8290
8628
  var w = this._clickTolerance(),
8291
8629
  p = new Point(w, w);
8630
+
8631
+ if (!this._rawPxBounds) {
8632
+ return;
8633
+ }
8634
+
8292
8635
  this._pxBounds = new Bounds([
8293
8636
  this._rawPxBounds.min.subtract(p),
8294
8637
  this._rawPxBounds.max.add(p)
@@ -8465,39 +8808,14 @@
8465
8808
  return !this._latlngs.length || !this._latlngs[0].length;
8466
8809
  },
8467
8810
 
8811
+ // @method getCenter(): LatLng
8812
+ // Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the Polygon.
8468
8813
  getCenter: function () {
8469
8814
  // throws error when not yet added to map as this center calculation requires projected coordinates
8470
8815
  if (!this._map) {
8471
8816
  throw new Error('Must add layer to map before using getCenter()');
8472
8817
  }
8473
-
8474
- var i, j, p1, p2, f, area, x, y, center,
8475
- points = this._rings[0],
8476
- len = points.length;
8477
-
8478
- if (!len) { return null; }
8479
-
8480
- // polygon centroid algorithm; only uses the first ring if there are multiple
8481
-
8482
- area = x = y = 0;
8483
-
8484
- for (i = 0, j = len - 1; i < len; j = i++) {
8485
- p1 = points[i];
8486
- p2 = points[j];
8487
-
8488
- f = p1.y * p2.x - p2.y * p1.x;
8489
- x += (p1.x + p2.x) * f;
8490
- y += (p1.y + p2.y) * f;
8491
- area += f * 3;
8492
- }
8493
-
8494
- if (area === 0) {
8495
- // Polygon is so small that all points are on same pixel.
8496
- center = points[0];
8497
- } else {
8498
- center = [x / area, y / area];
8499
- }
8500
- return this._map.layerPointToLatLng(center);
8818
+ return polygonCenter(this._defaultShape(), this._map.options.crs);
8501
8819
  },
8502
8820
 
8503
8821
  _convertLatLngs: function (latlngs) {
@@ -8782,14 +9100,24 @@
8782
9100
 
8783
9101
  case 'GeometryCollection':
8784
9102
  for (i = 0, len = geometry.geometries.length; i < len; i++) {
8785
- var layer = geometryToLayer({
9103
+ var geoLayer = geometryToLayer({
8786
9104
  geometry: geometry.geometries[i],
8787
9105
  type: 'Feature',
8788
9106
  properties: geojson.properties
8789
9107
  }, options);
8790
9108
 
8791
- if (layer) {
8792
- layers.push(layer);
9109
+ if (geoLayer) {
9110
+ layers.push(geoLayer);
9111
+ }
9112
+ }
9113
+ return new FeatureGroup(layers);
9114
+
9115
+ case 'FeatureCollection':
9116
+ for (i = 0, len = geometry.features.length; i < len; i++) {
9117
+ var featureLayer = geometryToLayer(geometry.features[i], options);
9118
+
9119
+ if (featureLayer) {
9120
+ layers.push(featureLayer);
8793
9121
  }
8794
9122
  }
8795
9123
  return new FeatureGroup(layers);
@@ -8830,29 +9158,32 @@
8830
9158
  return latlngs;
8831
9159
  }
8832
9160
 
8833
- // @function latLngToCoords(latlng: LatLng, precision?: Number): Array
9161
+ // @function latLngToCoords(latlng: LatLng, precision?: Number|false): Array
8834
9162
  // Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)
9163
+ // Coordinates values are rounded with [`formatNum`](#util-formatnum) function.
8835
9164
  function latLngToCoords(latlng, precision) {
8836
- precision = typeof precision === 'number' ? precision : 6;
9165
+ latlng = toLatLng(latlng);
8837
9166
  return latlng.alt !== undefined ?
8838
9167
  [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] :
8839
9168
  [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)];
8840
9169
  }
8841
9170
 
8842
- // @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array
9171
+ // @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean, precision?: Number|false): Array
8843
9172
  // Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)
8844
9173
  // `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default.
9174
+ // Coordinates values are rounded with [`formatNum`](#util-formatnum) function.
8845
9175
  function latLngsToCoords(latlngs, levelsDeep, closed, precision) {
8846
9176
  var coords = [];
8847
9177
 
8848
9178
  for (var i = 0, len = latlngs.length; i < len; i++) {
9179
+ // Check for flat arrays required to ensure unbalanced arrays are correctly converted in recursion
8849
9180
  coords.push(levelsDeep ?
8850
- latLngsToCoords(latlngs[i], levelsDeep - 1, closed, precision) :
9181
+ latLngsToCoords(latlngs[i], isFlat(latlngs[i]) ? 0 : levelsDeep - 1, closed, precision) :
8851
9182
  latLngToCoords(latlngs[i], precision));
8852
9183
  }
8853
9184
 
8854
- if (!levelsDeep && closed) {
8855
- coords.push(coords[0]);
9185
+ if (!levelsDeep && closed && coords.length > 0) {
9186
+ coords.push(coords[0].slice());
8856
9187
  }
8857
9188
 
8858
9189
  return coords;
@@ -8889,26 +9220,23 @@
8889
9220
 
8890
9221
  // @namespace Marker
8891
9222
  // @section Other methods
8892
- // @method toGeoJSON(precision?: Number): Object
8893
- // `precision` is the number of decimal places for coordinates.
8894
- // The default value is 6 places.
8895
- // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).
9223
+ // @method toGeoJSON(precision?: Number|false): Object
9224
+ // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
9225
+ // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).
8896
9226
  Marker.include(PointToGeoJSON);
8897
9227
 
8898
9228
  // @namespace CircleMarker
8899
- // @method toGeoJSON(precision?: Number): Object
8900
- // `precision` is the number of decimal places for coordinates.
8901
- // The default value is 6 places.
8902
- // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).
9229
+ // @method toGeoJSON(precision?: Number|false): Object
9230
+ // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
9231
+ // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).
8903
9232
  Circle.include(PointToGeoJSON);
8904
9233
  CircleMarker.include(PointToGeoJSON);
8905
9234
 
8906
9235
 
8907
9236
  // @namespace Polyline
8908
- // @method toGeoJSON(precision?: Number): Object
8909
- // `precision` is the number of decimal places for coordinates.
8910
- // The default value is 6 places.
8911
- // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).
9237
+ // @method toGeoJSON(precision?: Number|false): Object
9238
+ // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
9239
+ // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).
8912
9240
  Polyline.include({
8913
9241
  toGeoJSON: function (precision) {
8914
9242
  var multi = !isFlat(this._latlngs);
@@ -8923,10 +9251,9 @@
8923
9251
  });
8924
9252
 
8925
9253
  // @namespace Polygon
8926
- // @method toGeoJSON(precision?: Number): Object
8927
- // `precision` is the number of decimal places for coordinates.
8928
- // The default value is 6 places.
8929
- // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).
9254
+ // @method toGeoJSON(precision?: Number|false): Object
9255
+ // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
9256
+ // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).
8930
9257
  Polygon.include({
8931
9258
  toGeoJSON: function (precision) {
8932
9259
  var holes = !isFlat(this._latlngs),
@@ -8961,10 +9288,9 @@
8961
9288
  });
8962
9289
  },
8963
9290
 
8964
- // @method toGeoJSON(precision?: Number): Object
8965
- // `precision` is the number of decimal places for coordinates.
8966
- // The default value is 6 places.
8967
- // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).
9291
+ // @method toGeoJSON(precision?: Number|false): Object
9292
+ // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
9293
+ // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).
8968
9294
  toGeoJSON: function (precision) {
8969
9295
 
8970
9296
  var type = this.feature && this.feature.geometry && this.feature.geometry.type;
@@ -9029,7 +9355,7 @@
9029
9355
  * @example
9030
9356
  *
9031
9357
  * ```js
9032
- * var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
9358
+ * var imageUrl = 'https://maps.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
9033
9359
  * imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
9034
9360
  * L.imageOverlay(imageUrl, imageBounds).addTo(map);
9035
9361
  * ```
@@ -9268,6 +9594,12 @@
9268
9594
  this._url = errorUrl;
9269
9595
  this._image.src = errorUrl;
9270
9596
  }
9597
+ },
9598
+
9599
+ // @method getCenter(): LatLng
9600
+ // Returns the center of the ImageOverlay.
9601
+ getCenter: function () {
9602
+ return this._bounds.getCenter();
9271
9603
  }
9272
9604
  });
9273
9605
 
@@ -9304,6 +9636,7 @@
9304
9636
  options: {
9305
9637
  // @option autoplay: Boolean = true
9306
9638
  // Whether the video starts playing automatically when loaded.
9639
+ // On some browsers autoplay will only work with `muted: true`
9307
9640
  autoplay: true,
9308
9641
 
9309
9642
  // @option loop: Boolean = true
@@ -9312,12 +9645,16 @@
9312
9645
 
9313
9646
  // @option keepAspectRatio: Boolean = true
9314
9647
  // Whether the video will save aspect ratio after the projection.
9315
- // Relevant for supported browsers. Browser compatibility- https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit
9648
+ // Relevant for supported browsers. See [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)
9316
9649
  keepAspectRatio: true,
9317
9650
 
9318
9651
  // @option muted: Boolean = false
9319
9652
  // Whether the video starts on mute when loaded.
9320
- muted: false
9653
+ muted: false,
9654
+
9655
+ // @option playsInline: Boolean = true
9656
+ // Mobile browsers will play the video right where it is instead of open it up in fullscreen mode.
9657
+ playsInline: true
9321
9658
  },
9322
9659
 
9323
9660
  _initImage: function () {
@@ -9354,6 +9691,7 @@
9354
9691
  vid.autoplay = !!this.options.autoplay;
9355
9692
  vid.loop = !!this.options.loop;
9356
9693
  vid.muted = !!this.options.muted;
9694
+ vid.playsInline = !!this.options.playsInline;
9357
9695
  for (var i = 0; i < this._url.length; i++) {
9358
9696
  var source = create$1('source');
9359
9697
  source.src = this._url[i];
@@ -9424,9 +9762,9 @@
9424
9762
 
9425
9763
  /*
9426
9764
  * @class DivOverlay
9427
- * @inherits Layer
9765
+ * @inherits Interactive layer
9428
9766
  * @aka L.DivOverlay
9429
- * Base model for L.Popup and L.Tooltip. Inherit from it for custom popup like plugins.
9767
+ * Base model for L.Popup and L.Tooltip. Inherit from it for custom overlays like plugins.
9430
9768
  */
9431
9769
 
9432
9770
  // @namespace DivOverlay
@@ -9435,24 +9773,82 @@
9435
9773
  // @section
9436
9774
  // @aka DivOverlay options
9437
9775
  options: {
9438
- // @option offset: Point = Point(0, 7)
9439
- // The offset of the popup position. Useful to control the anchor
9440
- // of the popup when opening it on some overlays.
9441
- offset: [0, 7],
9776
+ // @option interactive: Boolean = false
9777
+ // If true, the popup/tooltip will listen to the mouse events.
9778
+ interactive: false,
9779
+
9780
+ // @option offset: Point = Point(0, 0)
9781
+ // The offset of the overlay position.
9782
+ offset: [0, 0],
9442
9783
 
9443
9784
  // @option className: String = ''
9444
- // A custom CSS class name to assign to the popup.
9785
+ // A custom CSS class name to assign to the overlay.
9445
9786
  className: '',
9446
9787
 
9447
- // @option pane: String = 'popupPane'
9448
- // `Map pane` where the popup will be added.
9449
- pane: 'popupPane'
9788
+ // @option pane: String = undefined
9789
+ // `Map pane` where the overlay will be added.
9790
+ pane: undefined,
9791
+
9792
+ // @option content: String|HTMLElement|Function = ''
9793
+ // Sets the HTML content of the overlay while initializing. If a function is passed the source layer will be
9794
+ // passed to the function. The function should return a `String` or `HTMLElement` to be used in the overlay.
9795
+ content: ''
9450
9796
  },
9451
9797
 
9452
9798
  initialize: function (options, source) {
9453
- setOptions(this, options);
9799
+ if (options && (options instanceof LatLng || isArray(options))) {
9800
+ this._latlng = toLatLng(options);
9801
+ setOptions(this, source);
9802
+ } else {
9803
+ setOptions(this, options);
9804
+ this._source = source;
9805
+ }
9806
+ if (this.options.content) {
9807
+ this._content = this.options.content;
9808
+ }
9809
+ },
9810
+
9811
+ // @method openOn(map: Map): this
9812
+ // Adds the overlay to the map.
9813
+ // Alternative to `map.openPopup(popup)`/`.openTooltip(tooltip)`.
9814
+ openOn: function (map) {
9815
+ map = arguments.length ? map : this._source._map; // experimental, not the part of public api
9816
+ if (!map.hasLayer(this)) {
9817
+ map.addLayer(this);
9818
+ }
9819
+ return this;
9820
+ },
9821
+
9822
+ // @method close(): this
9823
+ // Closes the overlay.
9824
+ // Alternative to `map.closePopup(popup)`/`.closeTooltip(tooltip)`
9825
+ // and `layer.closePopup()`/`.closeTooltip()`.
9826
+ close: function () {
9827
+ if (this._map) {
9828
+ this._map.removeLayer(this);
9829
+ }
9830
+ return this;
9831
+ },
9832
+
9833
+ // @method toggle(layer?: Layer): this
9834
+ // Opens or closes the overlay bound to layer depending on its current state.
9835
+ // Argument may be omitted only for overlay bound to layer.
9836
+ // Alternative to `layer.togglePopup()`/`.toggleTooltip()`.
9837
+ toggle: function (layer) {
9838
+ if (this._map) {
9839
+ this.close();
9840
+ } else {
9841
+ if (arguments.length) {
9842
+ this._source = layer;
9843
+ } else {
9844
+ layer = this._source;
9845
+ }
9846
+ this._prepareOpen();
9454
9847
 
9455
- this._source = source;
9848
+ // open the overlay on the map
9849
+ this.openOn(layer._map);
9850
+ }
9851
+ return this;
9456
9852
  },
9457
9853
 
9458
9854
  onAdd: function (map) {
@@ -9475,6 +9871,11 @@
9475
9871
  }
9476
9872
 
9477
9873
  this.bringToFront();
9874
+
9875
+ if (this.options.interactive) {
9876
+ addClass(this._container, 'leaflet-interactive');
9877
+ this.addInteractiveTarget(this._container);
9878
+ }
9478
9879
  },
9479
9880
 
9480
9881
  onRemove: function (map) {
@@ -9484,17 +9885,22 @@
9484
9885
  } else {
9485
9886
  remove(this._container);
9486
9887
  }
9888
+
9889
+ if (this.options.interactive) {
9890
+ removeClass(this._container, 'leaflet-interactive');
9891
+ this.removeInteractiveTarget(this._container);
9892
+ }
9487
9893
  },
9488
9894
 
9489
- // @namespace Popup
9895
+ // @namespace DivOverlay
9490
9896
  // @method getLatLng: LatLng
9491
- // Returns the geographical point of popup.
9897
+ // Returns the geographical point of the overlay.
9492
9898
  getLatLng: function () {
9493
9899
  return this._latlng;
9494
9900
  },
9495
9901
 
9496
9902
  // @method setLatLng(latlng: LatLng): this
9497
- // Sets the geographical point where the popup will open.
9903
+ // Sets the geographical point where the overlay will open.
9498
9904
  setLatLng: function (latlng) {
9499
9905
  this._latlng = toLatLng(latlng);
9500
9906
  if (this._map) {
@@ -9505,13 +9911,14 @@
9505
9911
  },
9506
9912
 
9507
9913
  // @method getContent: String|HTMLElement
9508
- // Returns the content of the popup.
9914
+ // Returns the content of the overlay.
9509
9915
  getContent: function () {
9510
9916
  return this._content;
9511
9917
  },
9512
9918
 
9513
9919
  // @method setContent(htmlContent: String|HTMLElement|Function): this
9514
- // Sets the HTML content of the popup. If a function is passed the source layer will be passed to the function. The function should return a `String` or `HTMLElement` to be used in the popup.
9920
+ // Sets the HTML content of the overlay. If a function is passed the source layer will be passed to the function.
9921
+ // The function should return a `String` or `HTMLElement` to be used in the overlay.
9515
9922
  setContent: function (content) {
9516
9923
  this._content = content;
9517
9924
  this.update();
@@ -9519,13 +9926,13 @@
9519
9926
  },
9520
9927
 
9521
9928
  // @method getElement: String|HTMLElement
9522
- // Returns the HTML container of the popup.
9929
+ // Returns the HTML container of the overlay.
9523
9930
  getElement: function () {
9524
9931
  return this._container;
9525
9932
  },
9526
9933
 
9527
9934
  // @method update: null
9528
- // Updates the popup content, layout and position. Useful for updating the popup after something inside changed, e.g. image loaded.
9935
+ // Updates the overlay content, layout and position. Useful for updating the overlay after something inside changed, e.g. image loaded.
9529
9936
  update: function () {
9530
9937
  if (!this._map) { return; }
9531
9938
 
@@ -9553,13 +9960,13 @@
9553
9960
  },
9554
9961
 
9555
9962
  // @method isOpen: Boolean
9556
- // Returns `true` when the popup is visible on the map.
9963
+ // Returns `true` when the overlay is visible on the map.
9557
9964
  isOpen: function () {
9558
9965
  return !!this._map && this._map.hasLayer(this);
9559
9966
  },
9560
9967
 
9561
9968
  // @method bringToFront: this
9562
- // Brings this popup in front of other popups (in the same map pane).
9969
+ // Brings this overlay in front of other overlays (in the same map pane).
9563
9970
  bringToFront: function () {
9564
9971
  if (this._map) {
9565
9972
  toFront(this._container);
@@ -9568,7 +9975,7 @@
9568
9975
  },
9569
9976
 
9570
9977
  // @method bringToBack: this
9571
- // Brings this popup to the back of other popups (in the same map pane).
9978
+ // Brings this overlay to the back of other overlays (in the same map pane).
9572
9979
  bringToBack: function () {
9573
9980
  if (this._map) {
9574
9981
  toBack(this._container);
@@ -9576,36 +9983,45 @@
9576
9983
  return this;
9577
9984
  },
9578
9985
 
9579
- _prepareOpen: function (parent, layer, latlng) {
9580
- if (!(layer instanceof Layer)) {
9581
- latlng = layer;
9582
- layer = parent;
9583
- }
9986
+ // prepare bound overlay to open: update latlng pos / content source (for FeatureGroup)
9987
+ _prepareOpen: function (latlng) {
9988
+ var source = this._source;
9989
+ if (!source._map) { return false; }
9584
9990
 
9585
- if (layer instanceof FeatureGroup) {
9586
- for (var id in parent._layers) {
9587
- layer = parent._layers[id];
9588
- break;
9991
+ if (source instanceof FeatureGroup) {
9992
+ source = null;
9993
+ var layers = this._source._layers;
9994
+ for (var id in layers) {
9995
+ if (layers[id]._map) {
9996
+ source = layers[id];
9997
+ break;
9998
+ }
9589
9999
  }
10000
+ if (!source) { return false; } // Unable to get source layer.
10001
+
10002
+ // set overlay source to this layer
10003
+ this._source = source;
9590
10004
  }
9591
10005
 
9592
10006
  if (!latlng) {
9593
- if (layer.getCenter) {
9594
- latlng = layer.getCenter();
9595
- } else if (layer.getLatLng) {
9596
- latlng = layer.getLatLng();
10007
+ if (source.getCenter) {
10008
+ latlng = source.getCenter();
10009
+ } else if (source.getLatLng) {
10010
+ latlng = source.getLatLng();
10011
+ } else if (source.getBounds) {
10012
+ latlng = source.getBounds().getCenter();
9597
10013
  } else {
9598
10014
  throw new Error('Unable to get source layer LatLng.');
9599
10015
  }
9600
10016
  }
10017
+ this.setLatLng(latlng);
9601
10018
 
9602
- // set overlay source to this layer
9603
- this._source = layer;
9604
-
9605
- // update the overlay (content, layout, ect...)
9606
- this.update();
10019
+ if (this._map) {
10020
+ // update the overlay (content, layout, etc...)
10021
+ this.update();
10022
+ }
9607
10023
 
9608
- return latlng;
10024
+ return true;
9609
10025
  },
9610
10026
 
9611
10027
  _updateContent: function () {
@@ -9622,6 +10038,11 @@
9622
10038
  }
9623
10039
  node.appendChild(content);
9624
10040
  }
10041
+
10042
+ // @namespace DivOverlay
10043
+ // @section DivOverlay events
10044
+ // @event contentupdate: Event
10045
+ // Fired when the content of the overlay is updated
9625
10046
  this.fire('contentupdate');
9626
10047
  },
9627
10048
 
@@ -9641,7 +10062,7 @@
9641
10062
  var bottom = this._containerBottom = -offset.y,
9642
10063
  left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
9643
10064
 
9644
- // bottom position the popup in case the height of the popup changes (images loading etc)
10065
+ // bottom position the overlay in case the height of the overlay changes (images loading etc)
9645
10066
  this._container.style.bottom = bottom + 'px';
9646
10067
  this._container.style.left = left + 'px';
9647
10068
  },
@@ -9650,6 +10071,34 @@
9650
10071
  return [0, 0];
9651
10072
  }
9652
10073
 
10074
+ });
10075
+
10076
+ Map.include({
10077
+ _initOverlay: function (OverlayClass, content, latlng, options) {
10078
+ var overlay = content;
10079
+ if (!(overlay instanceof OverlayClass)) {
10080
+ overlay = new OverlayClass(options).setContent(content);
10081
+ }
10082
+ if (latlng) {
10083
+ overlay.setLatLng(latlng);
10084
+ }
10085
+ return overlay;
10086
+ }
10087
+ });
10088
+
10089
+
10090
+ Layer.include({
10091
+ _initOverlay: function (OverlayClass, old, content, options) {
10092
+ var overlay = content;
10093
+ if (overlay instanceof OverlayClass) {
10094
+ setOptions(overlay, options);
10095
+ overlay._source = this;
10096
+ } else {
10097
+ overlay = (old && !options) ? old : new OverlayClass(options, this);
10098
+ overlay.setContent(content);
10099
+ }
10100
+ return overlay;
10101
+ }
9653
10102
  });
9654
10103
 
9655
10104
  /*
@@ -9668,7 +10117,8 @@
9668
10117
  * marker.bindPopup(popupContent).openPopup();
9669
10118
  * ```
9670
10119
  * Path overlays like polylines also have a `bindPopup` method.
9671
- * Here's a more complicated way to open a popup on a map:
10120
+ *
10121
+ * A popup can be also standalone:
9672
10122
  *
9673
10123
  * ```js
9674
10124
  * var popup = L.popup()
@@ -9676,6 +10126,11 @@
9676
10126
  * .setContent('<p>Hello world!<br />This is a nice popup.</p>')
9677
10127
  * .openOn(map);
9678
10128
  * ```
10129
+ * or
10130
+ * ```js
10131
+ * var popup = L.popup(latlng, {content: '<p>Hello world!<br />This is a nice popup.</p>')
10132
+ * .openOn(map);
10133
+ * ```
9679
10134
  */
9680
10135
 
9681
10136
 
@@ -9685,6 +10140,14 @@
9685
10140
  // @section
9686
10141
  // @aka Popup options
9687
10142
  options: {
10143
+ // @option pane: String = 'popupPane'
10144
+ // `Map pane` where the popup will be added.
10145
+ pane: 'popupPane',
10146
+
10147
+ // @option offset: Point = Point(0, 7)
10148
+ // The offset of the popup position.
10149
+ offset: [0, 7],
10150
+
9688
10151
  // @option maxWidth: Number = 300
9689
10152
  // Max width of the popup, in pixels.
9690
10153
  maxWidth: 300,
@@ -9696,6 +10159,8 @@
9696
10159
  // @option maxHeight: Number = null
9697
10160
  // If set, creates a scrollable container of the given height
9698
10161
  // inside a popup if its content exceeds it.
10162
+ // The scrollable container can be styled using the
10163
+ // `leaflet-popup-scrolled` CSS class selector.
9699
10164
  maxHeight: null,
9700
10165
 
9701
10166
  // @option autoPan: Boolean = true
@@ -9747,10 +10212,17 @@
9747
10212
 
9748
10213
  // @namespace Popup
9749
10214
  // @method openOn(map: Map): this
9750
- // Adds the popup to the map and closes the previous one. The same as `map.openPopup(popup)`.
10215
+ // Alternative to `map.openPopup(popup)`.
10216
+ // Adds the popup to the map and closes the previous one.
9751
10217
  openOn: function (map) {
9752
- map.openPopup(this);
9753
- return this;
10218
+ map = arguments.length ? map : this._source._map; // experimental, not the part of public api
10219
+
10220
+ if (!map.hasLayer(this) && map._popup && map._popup.options.autoClose) {
10221
+ map.removeLayer(map._popup);
10222
+ }
10223
+ map._popup = this;
10224
+
10225
+ return DivOverlay.prototype.openOn.call(this, map);
9754
10226
  },
9755
10227
 
9756
10228
  onAdd: function (map) {
@@ -9801,7 +10273,7 @@
9801
10273
  var events = DivOverlay.prototype.getEvents.call(this);
9802
10274
 
9803
10275
  if (this.options.closeOnClick !== undefined ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
9804
- events.preclick = this._close;
10276
+ events.preclick = this.close;
9805
10277
  }
9806
10278
 
9807
10279
  if (this.options.keepInView) {
@@ -9811,12 +10283,6 @@
9811
10283
  return events;
9812
10284
  },
9813
10285
 
9814
- _close: function () {
9815
- if (this._map) {
9816
- this._map.closePopup(this);
9817
- }
9818
- },
9819
-
9820
10286
  _initLayout: function () {
9821
10287
  var prefix = 'leaflet-popup',
9822
10288
  container = this._container = create$1('div',
@@ -9835,10 +10301,15 @@
9835
10301
 
9836
10302
  if (this.options.closeButton) {
9837
10303
  var closeButton = this._closeButton = create$1('a', prefix + '-close-button', container);
10304
+ closeButton.setAttribute('role', 'button'); // overrides the implicit role=link of <a> elements #7399
10305
+ closeButton.setAttribute('aria-label', 'Close popup');
9838
10306
  closeButton.href = '#close';
9839
- closeButton.innerHTML = '&#215;';
10307
+ closeButton.innerHTML = '<span aria-hidden="true">&#215;</span>';
9840
10308
 
9841
- on(closeButton, 'click', this._onCloseButtonClick, this);
10309
+ on(closeButton, 'click', function (ev) {
10310
+ preventDefault(ev);
10311
+ this.close();
10312
+ }, this);
9842
10313
  }
9843
10314
  },
9844
10315
 
@@ -9882,6 +10353,13 @@
9882
10353
  if (!this.options.autoPan) { return; }
9883
10354
  if (this._map._panAnim) { this._map._panAnim.stop(); }
9884
10355
 
10356
+ // We can endlessly recurse if keepInView is set and the view resets.
10357
+ // Let's guard against that by exiting early if we're responding to our own autopan.
10358
+ if (this._autopanning) {
10359
+ this._autopanning = false;
10360
+ return;
10361
+ }
10362
+
9885
10363
  var map = this._map,
9886
10364
  marginBottom = parseInt(getStyle(this._container, 'marginBottom'), 10) || 0,
9887
10365
  containerHeight = this._container.offsetHeight + marginBottom,
@@ -9916,17 +10394,17 @@
9916
10394
  // @event autopanstart: Event
9917
10395
  // Fired when the map starts autopanning when opening a popup.
9918
10396
  if (dx || dy) {
10397
+ // Track that we're autopanning, as this function will be re-ran on moveend
10398
+ if (this.options.keepInView) {
10399
+ this._autopanning = true;
10400
+ }
10401
+
9919
10402
  map
9920
10403
  .fire('autopanstart')
9921
10404
  .panBy([dx, dy]);
9922
10405
  }
9923
10406
  },
9924
10407
 
9925
- _onCloseButtonClick: function (e) {
9926
- this._close();
9927
- stop(e);
9928
- },
9929
-
9930
10408
  _getAnchor: function () {
9931
10409
  // Where should we anchor the popup on the source layer?
9932
10410
  return toPoint(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);
@@ -9937,6 +10415,9 @@
9937
10415
  // @namespace Popup
9938
10416
  // @factory L.popup(options?: Popup options, source?: Layer)
9939
10417
  // Instantiates a `Popup` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the popup with a reference to the Layer to which it refers.
10418
+ // @alternative
10419
+ // @factory L.popup(latlng: LatLng, options?: Popup options)
10420
+ // Instantiates a `Popup` object given `latlng` where the popup will open and an optional `options` object that describes its appearance and location.
9940
10421
  var popup = function (options, source) {
9941
10422
  return new Popup(options, source);
9942
10423
  };
@@ -9961,35 +10442,18 @@
9961
10442
  // @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this
9962
10443
  // Creates a popup with the specified content and options and opens it in the given point on a map.
9963
10444
  openPopup: function (popup, latlng, options) {
9964
- if (!(popup instanceof Popup)) {
9965
- popup = new Popup(options).setContent(popup);
9966
- }
9967
-
9968
- if (latlng) {
9969
- popup.setLatLng(latlng);
9970
- }
10445
+ this._initOverlay(Popup, popup, latlng, options)
10446
+ .openOn(this);
9971
10447
 
9972
- if (this.hasLayer(popup)) {
9973
- return this;
9974
- }
9975
-
9976
- if (this._popup && this._popup.options.autoClose) {
9977
- this.closePopup();
9978
- }
9979
-
9980
- this._popup = popup;
9981
- return this.addLayer(popup);
10448
+ return this;
9982
10449
  },
9983
10450
 
9984
10451
  // @method closePopup(popup?: Popup): this
9985
10452
  // Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).
9986
10453
  closePopup: function (popup) {
9987
- if (!popup || popup === this._popup) {
9988
- popup = this._popup;
9989
- this._popup = null;
9990
- }
10454
+ popup = arguments.length ? popup : this._popup;
9991
10455
  if (popup) {
9992
- this.removeLayer(popup);
10456
+ popup.close();
9993
10457
  }
9994
10458
  return this;
9995
10459
  }
@@ -10018,18 +10482,7 @@
10018
10482
  // necessary event listeners. If a `Function` is passed it will receive
10019
10483
  // the layer as the first argument and should return a `String` or `HTMLElement`.
10020
10484
  bindPopup: function (content, options) {
10021
-
10022
- if (content instanceof Popup) {
10023
- setOptions(content, options);
10024
- this._popup = content;
10025
- content._source = this;
10026
- } else {
10027
- if (!this._popup || options) {
10028
- this._popup = new Popup(options, this);
10029
- }
10030
- this._popup.setContent(content);
10031
- }
10032
-
10485
+ this._popup = this._initOverlay(Popup, this._popup, content, options);
10033
10486
  if (!this._popupHandlersAdded) {
10034
10487
  this.on({
10035
10488
  click: this._openPopup,
@@ -10061,14 +10514,16 @@
10061
10514
 
10062
10515
  // @method openPopup(latlng?: LatLng): this
10063
10516
  // Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed.
10064
- openPopup: function (layer, latlng) {
10065
- if (this._popup && this._map) {
10066
- latlng = this._popup._prepareOpen(this, layer, latlng);
10067
-
10068
- // open the popup on the map
10069
- this._map.openPopup(this._popup, latlng);
10517
+ openPopup: function (latlng) {
10518
+ if (this._popup) {
10519
+ if (!(this instanceof FeatureGroup)) {
10520
+ this._popup._source = this;
10521
+ }
10522
+ if (this._popup._prepareOpen(latlng || this._latlng)) {
10523
+ // open the popup on the map
10524
+ this._popup.openOn(this._map);
10525
+ }
10070
10526
  }
10071
-
10072
10527
  return this;
10073
10528
  },
10074
10529
 
@@ -10076,20 +10531,16 @@
10076
10531
  // Closes the popup bound to this layer if it is open.
10077
10532
  closePopup: function () {
10078
10533
  if (this._popup) {
10079
- this._popup._close();
10534
+ this._popup.close();
10080
10535
  }
10081
10536
  return this;
10082
10537
  },
10083
10538
 
10084
10539
  // @method togglePopup(): this
10085
10540
  // Opens or closes the popup bound to this layer depending on its current state.
10086
- togglePopup: function (target) {
10541
+ togglePopup: function () {
10087
10542
  if (this._popup) {
10088
- if (this._popup._map) {
10089
- this.closePopup();
10090
- } else {
10091
- this.openPopup(target);
10092
- }
10543
+ this._popup.toggle(this);
10093
10544
  }
10094
10545
  return this;
10095
10546
  },
@@ -10116,33 +10567,25 @@
10116
10567
  },
10117
10568
 
10118
10569
  _openPopup: function (e) {
10119
- var layer = e.layer || e.target;
10120
-
10121
- if (!this._popup) {
10122
- return;
10123
- }
10124
-
10125
- if (!this._map) {
10570
+ if (!this._popup || !this._map) {
10126
10571
  return;
10127
10572
  }
10128
-
10129
10573
  // prevent map click
10130
10574
  stop(e);
10131
10575
 
10132
- // if this inherits from Path its a vector and we can just
10133
- // open the popup at the new location
10134
- if (layer instanceof Path) {
10135
- this.openPopup(e.layer || e.target, e.latlng);
10576
+ var target = e.layer || e.target;
10577
+ if (this._popup._source === target && !(target instanceof Path)) {
10578
+ // treat it like a marker and figure out
10579
+ // if we should toggle it open/closed
10580
+ if (this._map.hasLayer(this._popup)) {
10581
+ this.closePopup();
10582
+ } else {
10583
+ this.openPopup(e.latlng);
10584
+ }
10136
10585
  return;
10137
10586
  }
10138
-
10139
- // otherwise treat it like a marker and figure out
10140
- // if we should toggle it open/closed
10141
- if (this._map.hasLayer(this._popup) && this._popup._source === layer) {
10142
- this.closePopup();
10143
- } else {
10144
- this.openPopup(layer, e.latlng);
10145
- }
10587
+ this._popup._source = target;
10588
+ this.openPopup(e.latlng);
10146
10589
  },
10147
10590
 
10148
10591
  _movePopup: function (e) {
@@ -10162,11 +10605,29 @@
10162
10605
  * @aka L.Tooltip
10163
10606
  * Used to display small texts on top of map layers.
10164
10607
  *
10165
- * @example
10608
+ * @example
10609
+ * If you want to just bind a tooltip to marker:
10610
+ *
10611
+ * ```js
10612
+ * marker.bindTooltip("my tooltip text").openTooltip();
10613
+ * ```
10614
+ * Path overlays like polylines also have a `bindTooltip` method.
10615
+ *
10616
+ * A tooltip can be also standalone:
10166
10617
  *
10167
10618
  * ```js
10168
- * marker.bindTooltip("my tooltip text").openTooltip();
10619
+ * var tooltip = L.tooltip()
10620
+ * .setLatLng(latlng)
10621
+ * .setContent('Hello world!<br />This is a nice tooltip.')
10622
+ * .addTo(map);
10623
+ * ```
10624
+ * or
10625
+ * ```js
10626
+ * var tooltip = L.tooltip(latlng, {content: 'Hello world!<br />This is a nice tooltip.'})
10627
+ * .addTo(map);
10169
10628
  * ```
10629
+ *
10630
+ *
10170
10631
  * Note about tooltip offset. Leaflet takes two options in consideration
10171
10632
  * for computing tooltip offsetting:
10172
10633
  * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.
@@ -10206,10 +10667,6 @@
10206
10667
  // If true, the tooltip will follow the mouse instead of being fixed at the feature center.
10207
10668
  sticky: false,
10208
10669
 
10209
- // @option interactive: Boolean = false
10210
- // If true, the tooltip will listen to the feature events.
10211
- interactive: false,
10212
-
10213
10670
  // @option opacity: Number = 0.9
10214
10671
  // Tooltip container opacity.
10215
10672
  opacity: 0.9
@@ -10226,6 +10683,8 @@
10226
10683
  map.fire('tooltipopen', {tooltip: this});
10227
10684
 
10228
10685
  if (this._source) {
10686
+ this.addEventParent(this._source);
10687
+
10229
10688
  // @namespace Layer
10230
10689
  // @section Tooltip events
10231
10690
  // @event tooltipopen: TooltipEvent
@@ -10244,6 +10703,8 @@
10244
10703
  map.fire('tooltipclose', {tooltip: this});
10245
10704
 
10246
10705
  if (this._source) {
10706
+ this.removeEventParent(this._source);
10707
+
10247
10708
  // @namespace Layer
10248
10709
  // @section Tooltip events
10249
10710
  // @event tooltipclose: TooltipEvent
@@ -10255,24 +10716,21 @@
10255
10716
  getEvents: function () {
10256
10717
  var events = DivOverlay.prototype.getEvents.call(this);
10257
10718
 
10258
- if (touch && !this.options.permanent) {
10259
- events.preclick = this._close;
10719
+ if (!this.options.permanent) {
10720
+ events.preclick = this.close;
10260
10721
  }
10261
10722
 
10262
10723
  return events;
10263
10724
  },
10264
10725
 
10265
- _close: function () {
10266
- if (this._map) {
10267
- this._map.closeTooltip(this);
10268
- }
10269
- },
10270
-
10271
10726
  _initLayout: function () {
10272
10727
  var prefix = 'leaflet-tooltip',
10273
10728
  className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
10274
10729
 
10275
10730
  this._contentNode = this._container = create$1('div', className);
10731
+
10732
+ this._container.setAttribute('role', 'tooltip');
10733
+ this._container.setAttribute('id', 'leaflet-tooltip-' + stamp(this));
10276
10734
  },
10277
10735
 
10278
10736
  _updateLayout: function () {},
@@ -10353,7 +10811,10 @@
10353
10811
 
10354
10812
  // @namespace Tooltip
10355
10813
  // @factory L.tooltip(options?: Tooltip options, source?: Layer)
10356
- // Instantiates a Tooltip object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.
10814
+ // Instantiates a `Tooltip` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.
10815
+ // @alternative
10816
+ // @factory L.tooltip(latlng: LatLng, options?: Tooltip options)
10817
+ // Instantiates a `Tooltip` object given `latlng` where the tooltip will open and an optional `options` object that describes its appearance and location.
10357
10818
  var tooltip = function (options, source) {
10358
10819
  return new Tooltip(options, source);
10359
10820
  };
@@ -10368,27 +10829,16 @@
10368
10829
  // @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
10369
10830
  // Creates a tooltip with the specified content and options and open it.
10370
10831
  openTooltip: function (tooltip, latlng, options) {
10371
- if (!(tooltip instanceof Tooltip)) {
10372
- tooltip = new Tooltip(options).setContent(tooltip);
10373
- }
10832
+ this._initOverlay(Tooltip, tooltip, latlng, options)
10833
+ .openOn(this);
10374
10834
 
10375
- if (latlng) {
10376
- tooltip.setLatLng(latlng);
10377
- }
10378
-
10379
- if (this.hasLayer(tooltip)) {
10380
- return this;
10381
- }
10382
-
10383
- return this.addLayer(tooltip);
10835
+ return this;
10384
10836
  },
10385
10837
 
10386
- // @method closeTooltip(tooltip?: Tooltip): this
10838
+ // @method closeTooltip(tooltip: Tooltip): this
10387
10839
  // Closes the tooltip given as parameter.
10388
10840
  closeTooltip: function (tooltip) {
10389
- if (tooltip) {
10390
- this.removeLayer(tooltip);
10391
- }
10841
+ tooltip.close();
10392
10842
  return this;
10393
10843
  }
10394
10844
 
@@ -10416,18 +10866,11 @@
10416
10866
  // the layer as the first argument and should return a `String` or `HTMLElement`.
10417
10867
  bindTooltip: function (content, options) {
10418
10868
 
10419
- if (content instanceof Tooltip) {
10420
- setOptions(content, options);
10421
- this._tooltip = content;
10422
- content._source = this;
10423
- } else {
10424
- if (!this._tooltip || options) {
10425
- this._tooltip = new Tooltip(options, this);
10426
- }
10427
- this._tooltip.setContent(content);
10428
-
10869
+ if (this._tooltip && this.isTooltipOpen()) {
10870
+ this.unbindTooltip();
10429
10871
  }
10430
10872
 
10873
+ this._tooltip = this._initOverlay(Tooltip, this._tooltip, content, options);
10431
10874
  this._initTooltipInteractions();
10432
10875
 
10433
10876
  if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {
@@ -10448,9 +10891,9 @@
10448
10891
  return this;
10449
10892
  },
10450
10893
 
10451
- _initTooltipInteractions: function (remove$$1) {
10452
- if (!remove$$1 && this._tooltipHandlersAdded) { return; }
10453
- var onOff = remove$$1 ? 'off' : 'on',
10894
+ _initTooltipInteractions: function (remove) {
10895
+ if (!remove && this._tooltipHandlersAdded) { return; }
10896
+ var onOff = remove ? 'off' : 'on',
10454
10897
  events = {
10455
10898
  remove: this.closeTooltip,
10456
10899
  move: this._moveTooltip
@@ -10458,36 +10901,40 @@
10458
10901
  if (!this._tooltip.options.permanent) {
10459
10902
  events.mouseover = this._openTooltip;
10460
10903
  events.mouseout = this.closeTooltip;
10461
- if (this._tooltip.options.sticky) {
10462
- events.mousemove = this._moveTooltip;
10463
- }
10464
- if (touch) {
10465
- events.click = this._openTooltip;
10904
+ events.click = this._openTooltip;
10905
+ if (this._map) {
10906
+ this._addFocusListeners();
10907
+ } else {
10908
+ events.add = this._addFocusListeners;
10466
10909
  }
10467
10910
  } else {
10468
10911
  events.add = this._openTooltip;
10469
10912
  }
10913
+ if (this._tooltip.options.sticky) {
10914
+ events.mousemove = this._moveTooltip;
10915
+ }
10470
10916
  this[onOff](events);
10471
- this._tooltipHandlersAdded = !remove$$1;
10917
+ this._tooltipHandlersAdded = !remove;
10472
10918
  },
10473
10919
 
10474
10920
  // @method openTooltip(latlng?: LatLng): this
10475
10921
  // Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.
10476
- openTooltip: function (layer, latlng) {
10477
- if (this._tooltip && this._map) {
10478
- latlng = this._tooltip._prepareOpen(this, layer, latlng);
10479
-
10480
- // open the tooltip on the map
10481
- this._map.openTooltip(this._tooltip, latlng);
10482
-
10483
- // Tooltip container may not be defined if not permanent and never
10484
- // opened.
10485
- if (this._tooltip.options.interactive && this._tooltip._container) {
10486
- addClass(this._tooltip._container, 'leaflet-clickable');
10487
- this.addInteractiveTarget(this._tooltip._container);
10922
+ openTooltip: function (latlng) {
10923
+ if (this._tooltip) {
10924
+ if (!(this instanceof FeatureGroup)) {
10925
+ this._tooltip._source = this;
10926
+ }
10927
+ if (this._tooltip._prepareOpen(latlng)) {
10928
+ // open the tooltip on the map
10929
+ this._tooltip.openOn(this._map);
10930
+
10931
+ if (this.getElement) {
10932
+ this._setAriaDescribedByOnLayer(this);
10933
+ } else if (this.eachLayer) {
10934
+ this.eachLayer(this._setAriaDescribedByOnLayer, this);
10935
+ }
10488
10936
  }
10489
10937
  }
10490
-
10491
10938
  return this;
10492
10939
  },
10493
10940
 
@@ -10495,24 +10942,15 @@
10495
10942
  // Closes the tooltip bound to this layer if it is open.
10496
10943
  closeTooltip: function () {
10497
10944
  if (this._tooltip) {
10498
- this._tooltip._close();
10499
- if (this._tooltip.options.interactive && this._tooltip._container) {
10500
- removeClass(this._tooltip._container, 'leaflet-clickable');
10501
- this.removeInteractiveTarget(this._tooltip._container);
10502
- }
10945
+ return this._tooltip.close();
10503
10946
  }
10504
- return this;
10505
10947
  },
10506
10948
 
10507
10949
  // @method toggleTooltip(): this
10508
10950
  // Opens or closes the tooltip bound to this layer depending on its current state.
10509
- toggleTooltip: function (target) {
10951
+ toggleTooltip: function () {
10510
10952
  if (this._tooltip) {
10511
- if (this._tooltip._map) {
10512
- this.closeTooltip();
10513
- } else {
10514
- this.openTooltip(target);
10515
- }
10953
+ this._tooltip.toggle(this);
10516
10954
  }
10517
10955
  return this;
10518
10956
  },
@@ -10538,13 +10976,52 @@
10538
10976
  return this._tooltip;
10539
10977
  },
10540
10978
 
10541
- _openTooltip: function (e) {
10542
- var layer = e.layer || e.target;
10979
+ _addFocusListeners: function () {
10980
+ if (this.getElement) {
10981
+ this._addFocusListenersOnLayer(this);
10982
+ } else if (this.eachLayer) {
10983
+ this.eachLayer(this._addFocusListenersOnLayer, this);
10984
+ }
10985
+ },
10986
+
10987
+ _addFocusListenersOnLayer: function (layer) {
10988
+ var el = typeof layer.getElement === 'function' && layer.getElement();
10989
+ if (el) {
10990
+ on(el, 'focus', function () {
10991
+ this._tooltip._source = layer;
10992
+ this.openTooltip();
10993
+ }, this);
10994
+ on(el, 'blur', this.closeTooltip, this);
10995
+ }
10996
+ },
10997
+
10998
+ _setAriaDescribedByOnLayer: function (layer) {
10999
+ var el = typeof layer.getElement === 'function' && layer.getElement();
11000
+ if (el) {
11001
+ el.setAttribute('aria-describedby', this._tooltip._container.id);
11002
+ }
11003
+ },
11004
+
10543
11005
 
11006
+ _openTooltip: function (e) {
10544
11007
  if (!this._tooltip || !this._map) {
10545
11008
  return;
10546
11009
  }
10547
- this.openTooltip(layer, this._tooltip.options.sticky ? e.latlng : undefined);
11010
+
11011
+ // If the map is moving, we will show the tooltip after it's done.
11012
+ if (this._map.dragging && this._map.dragging.moving() && !this._openOnceFlag) {
11013
+ this._openOnceFlag = true;
11014
+ var that = this;
11015
+ this._map.once('moveend', function () {
11016
+ that._openOnceFlag = false;
11017
+ that._openTooltip(e);
11018
+ });
11019
+ return;
11020
+ }
11021
+
11022
+ this._tooltip._source = e.layer || e.target;
11023
+
11024
+ this.openTooltip(this._tooltip.options.sticky ? e.latlng : undefined);
10548
11025
  },
10549
11026
 
10550
11027
  _moveTooltip: function (e) {
@@ -10715,7 +11192,7 @@
10715
11192
  // `true` by default on mobile browsers, in order to avoid too many requests and keep smooth navigation.
10716
11193
  // `false` otherwise in order to display new tiles _during_ panning, since it is easy to pan outside the
10717
11194
  // [`keepBuffer`](#gridlayer-keepbuffer) option in desktop browsers.
10718
- updateWhenIdle: mobile,
11195
+ updateWhenIdle: Browser.mobile,
10719
11196
 
10720
11197
  // @option updateWhenZooming: Boolean = true
10721
11198
  // By default, a smooth zoom animation (during a [touch zoom](#map-touchzoom) or a [`flyTo()`](#map-flyto)) will update grid layers every integer zoom level. Setting this option to `false` will update the grid layer only when the smooth animation ends.
@@ -10784,8 +11261,7 @@
10784
11261
  this._levels = {};
10785
11262
  this._tiles = {};
10786
11263
 
10787
- this._resetView();
10788
- this._update();
11264
+ this._resetView(); // implicit _update() call
10789
11265
  },
10790
11266
 
10791
11267
  beforeAdd: function (map) {
@@ -10854,6 +11330,11 @@
10854
11330
  redraw: function () {
10855
11331
  if (this._map) {
10856
11332
  this._removeAllTiles();
11333
+ var tileZoom = this._clampZoom(this._map.getZoom());
11334
+ if (tileZoom !== this._tileZoom) {
11335
+ this._tileZoom = tileZoom;
11336
+ this._updateLevels();
11337
+ }
10857
11338
  this._update();
10858
11339
  }
10859
11340
  return this;
@@ -10932,7 +11413,7 @@
10932
11413
  if (!this._map) { return; }
10933
11414
 
10934
11415
  // IE doesn't inherit filter opacity properly, so we're forced to set it on tiles
10935
- if (ielt9) { return; }
11416
+ if (Browser.ielt9) { return; }
10936
11417
 
10937
11418
  setOpacity(this._container, this.options.opacity);
10938
11419
 
@@ -11218,7 +11699,7 @@
11218
11699
  translate = level.origin.multiplyBy(scale)
11219
11700
  .subtract(this._map._getNewPixelOrigin(center, zoom)).round();
11220
11701
 
11221
- if (any3d) {
11702
+ if (Browser.any3d) {
11222
11703
  setTransform(level.el, translate, scale);
11223
11704
  } else {
11224
11705
  setPosition(level.el, translate);
@@ -11419,15 +11900,9 @@
11419
11900
  tile.onmousemove = falseFn;
11420
11901
 
11421
11902
  // update opacity on tiles in IE7-8 because of filter inheritance problems
11422
- if (ielt9 && this.options.opacity < 1) {
11903
+ if (Browser.ielt9 && this.options.opacity < 1) {
11423
11904
  setOpacity(tile, this.options.opacity);
11424
11905
  }
11425
-
11426
- // without this hack, tiles disappear after zoom on Chrome for Android
11427
- // https://github.com/Leaflet/Leaflet/issues/2078
11428
- if (android && !android23) {
11429
- tile.style.WebkitBackfaceVisibility = 'hidden';
11430
- }
11431
11906
  },
11432
11907
 
11433
11908
  _addTile: function (coords, container) {
@@ -11506,7 +11981,7 @@
11506
11981
  // Fired when the grid layer loaded all visible tiles.
11507
11982
  this.fire('load');
11508
11983
 
11509
- if (ielt9 || !this._map._fadeAnimated) {
11984
+ if (Browser.ielt9 || !this._map._fadeAnimated) {
11510
11985
  requestAnimFrame(this._pruneTiles, this);
11511
11986
  } else {
11512
11987
  // Wait a bit more than 0.2 secs (the duration of the tile fade-in)
@@ -11558,7 +12033,7 @@
11558
12033
  * @example
11559
12034
  *
11560
12035
  * ```js
11561
- * L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar', attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'}).addTo(map);
12036
+ * L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar', attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'}).addTo(map);
11562
12037
  * ```
11563
12038
  *
11564
12039
  * @section URL template
@@ -11567,7 +12042,7 @@
11567
12042
  * A string of the following form:
11568
12043
  *
11569
12044
  * ```
11570
- * 'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
12045
+ * 'https://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
11571
12046
  * ```
11572
12047
  *
11573
12048
  * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add "&commat;2x" to the URL to load retina tiles.
@@ -11575,7 +12050,7 @@
11575
12050
  * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:
11576
12051
  *
11577
12052
  * ```
11578
- * L.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});
12053
+ * L.tileLayer('https://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});
11579
12054
  * ```
11580
12055
  */
11581
12056
 
@@ -11621,7 +12096,15 @@
11621
12096
  // Whether the crossOrigin attribute will be added to the tiles.
11622
12097
  // If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.
11623
12098
  // Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
11624
- crossOrigin: false
12099
+ crossOrigin: false,
12100
+
12101
+ // @option referrerPolicy: Boolean|String = false
12102
+ // Whether the referrerPolicy attribute will be added to the tiles.
12103
+ // If a String is provided, all tiles will have their referrerPolicy attribute set to the String provided.
12104
+ // This may be needed if your map's rendering context has a strict default but your tile provider expects a valid referrer
12105
+ // (e.g. to validate an API token).
12106
+ // Refer to [HTMLImageElement.referrerPolicy](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/referrerPolicy) for valid String values.
12107
+ referrerPolicy: false
11625
12108
  },
11626
12109
 
11627
12110
  initialize: function (url, options) {
@@ -11631,29 +12114,32 @@
11631
12114
  options = setOptions(this, options);
11632
12115
 
11633
12116
  // detecting retina displays, adjusting tileSize and zoom levels
11634
- if (options.detectRetina && retina && options.maxZoom > 0) {
12117
+ if (options.detectRetina && Browser.retina && options.maxZoom > 0) {
11635
12118
 
11636
12119
  options.tileSize = Math.floor(options.tileSize / 2);
11637
12120
 
11638
12121
  if (!options.zoomReverse) {
11639
12122
  options.zoomOffset++;
11640
- options.maxZoom--;
12123
+ options.maxZoom = Math.max(options.minZoom, options.maxZoom - 1);
11641
12124
  } else {
11642
12125
  options.zoomOffset--;
11643
- options.minZoom++;
12126
+ options.minZoom = Math.min(options.maxZoom, options.minZoom + 1);
11644
12127
  }
11645
12128
 
11646
12129
  options.minZoom = Math.max(0, options.minZoom);
12130
+ } else if (!options.zoomReverse) {
12131
+ // make sure maxZoom is gte minZoom
12132
+ options.maxZoom = Math.max(options.minZoom, options.maxZoom);
12133
+ } else {
12134
+ // make sure minZoom is lte maxZoom
12135
+ options.minZoom = Math.min(options.maxZoom, options.minZoom);
11647
12136
  }
11648
12137
 
11649
12138
  if (typeof options.subdomains === 'string') {
11650
12139
  options.subdomains = options.subdomains.split('');
11651
12140
  }
11652
12141
 
11653
- // for https://github.com/Leaflet/Leaflet/issues/137
11654
- if (!android) {
11655
- this.on('tileunload', this._onTileRemove);
11656
- }
12142
+ this.on('tileunload', this._onTileRemove);
11657
12143
  },
11658
12144
 
11659
12145
  // @method setUrl(url: String, noRedraw?: Boolean): this
@@ -11687,17 +12173,17 @@
11687
12173
  tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
11688
12174
  }
11689
12175
 
11690
- /*
11691
- Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons
11692
- http://www.w3.org/TR/WCAG20-TECHS/H67
11693
- */
11694
- tile.alt = '';
12176
+ // for this new option we follow the documented behavior
12177
+ // more closely by only setting the property when string
12178
+ if (typeof this.options.referrerPolicy === 'string') {
12179
+ tile.referrerPolicy = this.options.referrerPolicy;
12180
+ }
11695
12181
 
11696
- /*
11697
- Set role="presentation" to force screen readers to ignore this
11698
- https://www.w3.org/TR/wai-aria/roles#textalternativecomputation
11699
- */
11700
- tile.setAttribute('role', 'presentation');
12182
+ // The alt attribute is set to the empty string,
12183
+ // allowing screen readers to ignore the decorative image tiles.
12184
+ // https://www.w3.org/WAI/tutorials/images/decorative/
12185
+ // https://www.w3.org/TR/html-aria/#el-img-empty-alt
12186
+ tile.alt = '';
11701
12187
 
11702
12188
  tile.src = this.getTileUrl(coords);
11703
12189
 
@@ -11712,7 +12198,7 @@
11712
12198
  // Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.
11713
12199
  getTileUrl: function (coords) {
11714
12200
  var data = {
11715
- r: retina ? '@2x' : '',
12201
+ r: Browser.retina ? '@2x' : '',
11716
12202
  s: this._getSubdomain(coords),
11717
12203
  x: coords.x,
11718
12204
  y: coords.y,
@@ -11731,7 +12217,7 @@
11731
12217
 
11732
12218
  _tileOnLoad: function (done, tile) {
11733
12219
  // For https://github.com/Leaflet/Leaflet/issues/3332
11734
- if (ielt9) {
12220
+ if (Browser.ielt9) {
11735
12221
  setTimeout(bind(done, this, null, tile), 0);
11736
12222
  } else {
11737
12223
  done(null, tile);
@@ -11780,8 +12266,15 @@
11780
12266
 
11781
12267
  if (!tile.complete) {
11782
12268
  tile.src = emptyImageUrl;
12269
+ var coords = this._tiles[i].coords;
11783
12270
  remove(tile);
11784
12271
  delete this._tiles[i];
12272
+ // @event tileabort: TileEvent
12273
+ // Fired when a tile was loading but is now not wanted.
12274
+ this.fire('tileabort', {
12275
+ tile: tile,
12276
+ coords: coords
12277
+ });
11785
12278
  }
11786
12279
  }
11787
12280
  }
@@ -11792,11 +12285,7 @@
11792
12285
  if (!tile) { return; }
11793
12286
 
11794
12287
  // Cancels any pending http requests associated with the tile
11795
- // unless we're on Android's stock browser,
11796
- // see https://github.com/Leaflet/Leaflet/issues/137
11797
- if (!androidStock) {
11798
- tile.el.setAttribute('src', emptyImageUrl);
11799
- }
12288
+ tile.el.setAttribute('src', emptyImageUrl);
11800
12289
 
11801
12290
  return GridLayer.prototype._removeTile.call(this, key);
11802
12291
  },
@@ -11842,7 +12331,7 @@
11842
12331
  // @aka TileLayer.WMS options
11843
12332
  // If any custom options not documented here are used, they will be sent to the
11844
12333
  // WMS server as extra parameters in each request URL. This can be useful for
11845
- // [non-standard vendor WMS parameters](http://docs.geoserver.org/stable/en/user/services/wms/vendor.html).
12334
+ // [non-standard vendor WMS parameters](https://docs.geoserver.org/stable/en/user/services/wms/vendor.html).
11846
12335
  defaultWmsParams: {
11847
12336
  service: 'WMS',
11848
12337
  request: 'GetMap',
@@ -11894,7 +12383,7 @@
11894
12383
 
11895
12384
  options = setOptions(this, options);
11896
12385
 
11897
- var realRetina = options.detectRetina && retina ? 2 : 1;
12386
+ var realRetina = options.detectRetina && Browser.retina ? 2 : 1;
11898
12387
  var tileSize = this.getTileSize();
11899
12388
  wmsParams.width = tileSize.x * realRetina;
11900
12389
  wmsParams.height = tileSize.y * realRetina;
@@ -11981,11 +12470,7 @@
11981
12470
  // @option padding: Number = 0.1
11982
12471
  // How much to extend the clip area around the map view (relative to its size)
11983
12472
  // e.g. 0.1 would be 10% of map view in each direction
11984
- padding: 0.1,
11985
-
11986
- // @option tolerance: Number = 0
11987
- // How much to extend click tolerance round a path/object on the map
11988
- tolerance : 0
12473
+ padding: 0.1
11989
12474
  },
11990
12475
 
11991
12476
  initialize: function (options) {
@@ -11998,9 +12483,8 @@
11998
12483
  if (!this._container) {
11999
12484
  this._initContainer(); // defined by renderer implementations
12000
12485
 
12001
- if (this._zoomAnimated) {
12002
- addClass(this._container, 'leaflet-zoom-animated');
12003
- }
12486
+ // always keep transform-origin as 0 0
12487
+ addClass(this._container, 'leaflet-zoom-animated');
12004
12488
  }
12005
12489
 
12006
12490
  this.getPane().appendChild(this._container);
@@ -12036,15 +12520,13 @@
12036
12520
 
12037
12521
  _updateTransform: function (center, zoom) {
12038
12522
  var scale = this._map.getZoomScale(zoom, this._zoom),
12039
- position = getPosition(this._container),
12040
12523
  viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),
12041
12524
  currentCenterPoint = this._map.project(this._center, zoom),
12042
- destCenterPoint = this._map.project(center, zoom),
12043
- centerOffset = destCenterPoint.subtract(currentCenterPoint),
12044
12525
 
12045
- topLeftOffset = viewHalf.multiplyBy(-scale).add(position).add(viewHalf).subtract(centerOffset);
12526
+ topLeftOffset = viewHalf.multiplyBy(-scale).add(currentCenterPoint)
12527
+ .subtract(this._map._getNewPixelOrigin(center, zoom));
12046
12528
 
12047
- if (any3d) {
12529
+ if (Browser.any3d) {
12048
12530
  setTransform(this._container, topLeftOffset, scale);
12049
12531
  } else {
12050
12532
  setPosition(this._container, topLeftOffset);
@@ -12094,7 +12576,7 @@
12094
12576
  * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
12095
12577
  * Inherits `Renderer`.
12096
12578
  *
12097
- * Due to [technical limitations](http://caniuse.com/#search=canvas), Canvas is not
12579
+ * Due to [technical limitations](https://caniuse.com/canvas), Canvas is not
12098
12580
  * available in all web browsers, notably IE8, and overlapping geometries might
12099
12581
  * not display properly in some edge cases.
12100
12582
  *
@@ -12119,6 +12601,15 @@
12119
12601
  */
12120
12602
 
12121
12603
  var Canvas = Renderer.extend({
12604
+
12605
+ // @section
12606
+ // @aka Canvas options
12607
+ options: {
12608
+ // @option tolerance: Number = 0
12609
+ // How much to extend the click tolerance around a path/object on the map.
12610
+ tolerance: 0
12611
+ },
12612
+
12122
12613
  getEvents: function () {
12123
12614
  var events = Renderer.prototype.getEvents.call(this);
12124
12615
  events.viewprereset = this._onViewPreReset;
@@ -12144,6 +12635,7 @@
12144
12635
  on(container, 'mousemove', this._onMouseMove, this);
12145
12636
  on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this);
12146
12637
  on(container, 'mouseout', this._handleMouseOut, this);
12638
+ container['_leaflet_disable_events'] = true;
12147
12639
 
12148
12640
  this._ctx = container.getContext('2d');
12149
12641
  },
@@ -12176,7 +12668,7 @@
12176
12668
  var b = this._bounds,
12177
12669
  container = this._container,
12178
12670
  size = b.getSize(),
12179
- m = retina ? 2 : 1;
12671
+ m = Browser.retina ? 2 : 1;
12180
12672
 
12181
12673
  setPosition(container, b.min);
12182
12674
 
@@ -12186,7 +12678,7 @@
12186
12678
  container.style.width = size.x + 'px';
12187
12679
  container.style.height = size.y + 'px';
12188
12680
 
12189
- if (retina) {
12681
+ if (Browser.retina) {
12190
12682
  this._ctx.scale(2, 2);
12191
12683
  }
12192
12684
 
@@ -12430,15 +12922,12 @@
12430
12922
  for (var order = this._drawFirst; order; order = order.next) {
12431
12923
  layer = order.layer;
12432
12924
  if (layer.options.interactive && layer._containsPoint(point)) {
12433
- if (!(e.type === 'click' || e.type !== 'preclick') || !this._map._draggableMoved(layer)) {
12925
+ if (!(e.type === 'click' || e.type === 'preclick') || !this._map._draggableMoved(layer)) {
12434
12926
  clickedLayer = layer;
12435
12927
  }
12436
12928
  }
12437
12929
  }
12438
- if (clickedLayer) {
12439
- fakeStop(e);
12440
- this._fireEvent([clickedLayer], e);
12441
- }
12930
+ this._fireEvent(clickedLayer ? [clickedLayer] : false, e);
12442
12931
  },
12443
12932
 
12444
12933
  _onMouseMove: function (e) {
@@ -12484,9 +12973,7 @@
12484
12973
  }
12485
12974
  }
12486
12975
 
12487
- if (this._hoveredLayer) {
12488
- this._fireEvent([this._hoveredLayer], e);
12489
- }
12976
+ this._fireEvent(this._hoveredLayer ? [this._hoveredLayer] : false, e);
12490
12977
 
12491
12978
  this._mouseHoverThrottled = true;
12492
12979
  setTimeout(bind(function () {
@@ -12563,8 +13050,8 @@
12563
13050
 
12564
13051
  // @factory L.canvas(options?: Renderer options)
12565
13052
  // Creates a Canvas renderer with the given options.
12566
- function canvas$1(options) {
12567
- return canvas ? new Canvas(options) : null;
13053
+ function canvas(options) {
13054
+ return Browser.canvas ? new Canvas(options) : null;
12568
13055
  }
12569
13056
 
12570
13057
  /*
@@ -12579,10 +13066,12 @@
12579
13066
  return document.createElement('<lvml:' + name + ' class="lvml">');
12580
13067
  };
12581
13068
  } catch (e) {
12582
- return function (name) {
12583
- return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
12584
- };
13069
+ // Do not return fn from catch block so `e` can be garbage collected
13070
+ // See https://github.com/Leaflet/Leaflet/pull/7279
12585
13071
  }
13072
+ return function (name) {
13073
+ return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
13074
+ };
12586
13075
  })();
12587
13076
 
12588
13077
 
@@ -12706,7 +13195,7 @@
12706
13195
  }
12707
13196
  };
12708
13197
 
12709
- var create$2 = vml ? vmlCreate : svgCreate;
13198
+ var create = Browser.vml ? vmlCreate : svgCreate;
12710
13199
 
12711
13200
  /*
12712
13201
  * @class SVG
@@ -12716,7 +13205,7 @@
12716
13205
  * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).
12717
13206
  * Inherits `Renderer`.
12718
13207
  *
12719
- * Due to [technical limitations](http://caniuse.com/#search=svg), SVG is not
13208
+ * Due to [technical limitations](https://caniuse.com/svg), SVG is not
12720
13209
  * available in all web browsers, notably Android 2.x and 3.x.
12721
13210
  *
12722
13211
  * Although SVG is not available on IE7 and IE8, these browsers support
@@ -12746,19 +13235,13 @@
12746
13235
 
12747
13236
  var SVG = Renderer.extend({
12748
13237
 
12749
- getEvents: function () {
12750
- var events = Renderer.prototype.getEvents.call(this);
12751
- events.zoomstart = this._onZoomStart;
12752
- return events;
12753
- },
12754
-
12755
13238
  _initContainer: function () {
12756
- this._container = create$2('svg');
13239
+ this._container = create('svg');
12757
13240
 
12758
13241
  // makes it possible to click through svg root; we'll reset it back in individual paths
12759
13242
  this._container.setAttribute('pointer-events', 'none');
12760
13243
 
12761
- this._rootGroup = create$2('g');
13244
+ this._rootGroup = create('g');
12762
13245
  this._container.appendChild(this._rootGroup);
12763
13246
  },
12764
13247
 
@@ -12770,13 +13253,6 @@
12770
13253
  delete this._svgSize;
12771
13254
  },
12772
13255
 
12773
- _onZoomStart: function () {
12774
- // Drag-then-pinch interactions might mess up the center and zoom.
12775
- // In this case, the easiest way to prevent this is re-do the renderer
12776
- // bounds and padding when the zooming starts.
12777
- this._update();
12778
- },
12779
-
12780
13256
  _update: function () {
12781
13257
  if (this._map._animatingZoom && this._bounds) { return; }
12782
13258
 
@@ -12803,7 +13279,7 @@
12803
13279
  // methods below are called by vector layers implementations
12804
13280
 
12805
13281
  _initPath: function (layer) {
12806
- var path = layer._path = create$2('path');
13282
+ var path = layer._path = create('path');
12807
13283
 
12808
13284
  // @namespace Path
12809
13285
  // @option className: String = null
@@ -12907,15 +13383,15 @@
12907
13383
  }
12908
13384
  });
12909
13385
 
12910
- if (vml) {
13386
+ if (Browser.vml) {
12911
13387
  SVG.include(vmlMixin);
12912
13388
  }
12913
13389
 
12914
13390
  // @namespace SVG
12915
13391
  // @factory L.svg(options?: Renderer options)
12916
13392
  // Creates a SVG renderer with the given options.
12917
- function svg$1(options) {
12918
- return svg || vml ? new SVG(options) : null;
13393
+ function svg(options) {
13394
+ return Browser.svg || Browser.vml ? new SVG(options) : null;
12919
13395
  }
12920
13396
 
12921
13397
  Map.include({
@@ -12956,7 +13432,7 @@
12956
13432
  // @namespace Map; @option preferCanvas: Boolean = false
12957
13433
  // Whether `Path`s should be rendered on a `Canvas` renderer.
12958
13434
  // By default, all `Path`s are rendered in a `SVG` renderer.
12959
- return (this.options.preferCanvas && canvas$1(options)) || svg$1(options);
13435
+ return (this.options.preferCanvas && canvas(options)) || svg(options);
12960
13436
  }
12961
13437
  });
12962
13438
 
@@ -13015,7 +13491,7 @@
13015
13491
  return new Rectangle(latLngBounds, options);
13016
13492
  }
13017
13493
 
13018
- SVG.create = create$2;
13494
+ SVG.create = create;
13019
13495
  SVG.pointsToPath = pointsToPath;
13020
13496
 
13021
13497
  GeoJSON.geometryToLayer = geometryToLayer;
@@ -13160,6 +13636,8 @@
13160
13636
  _onKeyDown: function (e) {
13161
13637
  if (e.keyCode === 27) {
13162
13638
  this._finish();
13639
+ this._clearDeferredResetState();
13640
+ this._resetState();
13163
13641
  }
13164
13642
  }
13165
13643
  });
@@ -13230,7 +13708,7 @@
13230
13708
  // @section Interaction Options
13231
13709
  Map.mergeOptions({
13232
13710
  // @option dragging: Boolean = true
13233
- // Whether the map be draggable with mouse/touch or not.
13711
+ // Whether the map is draggable with mouse/touch or not.
13234
13712
  dragging: true,
13235
13713
 
13236
13714
  // @section Panning Inertia Options
@@ -13238,8 +13716,8 @@
13238
13716
  // If enabled, panning of the map will have an inertia effect where
13239
13717
  // the map builds momentum while dragging and continues moving in
13240
13718
  // the same direction for some time. Feels especially nice on touch
13241
- // devices. Enabled by default unless running on old Android devices.
13242
- inertia: !android23,
13719
+ // devices. Enabled by default.
13720
+ inertia: true,
13243
13721
 
13244
13722
  // @option inertiaDeceleration: Number = 3000
13245
13723
  // The rate with which the inertial movement slows down, in pixels/second².
@@ -13403,7 +13881,7 @@
13403
13881
  var map = this._map,
13404
13882
  options = map.options,
13405
13883
 
13406
- noInertia = !options.inertia || this._times.length < 2;
13884
+ noInertia = !options.inertia || e.noInertia || this._times.length < 2;
13407
13885
 
13408
13886
  map.fire('dragend', e);
13409
13887
 
@@ -13597,10 +14075,15 @@
13597
14075
  offset = toPoint(offset).multiplyBy(3);
13598
14076
  }
13599
14077
 
13600
- map.panBy(offset);
13601
-
13602
14078
  if (map.options.maxBounds) {
13603
- map.panInsideBounds(map.options.maxBounds);
14079
+ offset = map._limitOffset(toPoint(offset), map.options.maxBounds);
14080
+ }
14081
+
14082
+ if (map.options.worldCopyJump) {
14083
+ var newLatLng = map.wrapLatLng(map.unproject(map.project(map.getCenter()).add(offset)));
14084
+ map.panTo(newLatLng);
14085
+ } else {
14086
+ map.panBy(offset);
13604
14087
  }
13605
14088
  }
13606
14089
  } else if (key in this._zoomKeys) {
@@ -13711,17 +14194,19 @@
13711
14194
  Map.addInitHook('addHandler', 'scrollWheelZoom', ScrollWheelZoom);
13712
14195
 
13713
14196
  /*
13714
- * L.Map.Tap is used to enable mobile hacks like quick taps and long hold.
14197
+ * L.Map.TapHold is used to simulate `contextmenu` event on long hold,
14198
+ * which otherwise is not fired by mobile Safari.
13715
14199
  */
13716
14200
 
14201
+ var tapHoldDelay = 600;
14202
+
13717
14203
  // @namespace Map
13718
14204
  // @section Interaction Options
13719
14205
  Map.mergeOptions({
13720
14206
  // @section Touch interaction options
13721
- // @option tap: Boolean = true
13722
- // Enables mobile hacks for supporting instant taps (fixing 200ms click
13723
- // delay on iOS/Android) and touch holds (fired as `contextmenu` events).
13724
- tap: true,
14207
+ // @option tapHold: Boolean
14208
+ // Enables simulation of `contextmenu` event, default is `true` for mobile Safari.
14209
+ tapHold: Browser.touchNative && Browser.safari && Browser.mobile,
13725
14210
 
13726
14211
  // @option tapTolerance: Number = 15
13727
14212
  // The max number of pixels a user can shift his finger during touch
@@ -13729,7 +14214,7 @@
13729
14214
  tapTolerance: 15
13730
14215
  });
13731
14216
 
13732
- var Tap = Handler.extend({
14217
+ var TapHold = Handler.extend({
13733
14218
  addHooks: function () {
13734
14219
  on(this._map._container, 'touchstart', this._onDown, this);
13735
14220
  },
@@ -13739,104 +14224,70 @@
13739
14224
  },
13740
14225
 
13741
14226
  _onDown: function (e) {
13742
- if (!e.touches) { return; }
13743
-
13744
- preventDefault(e);
13745
-
13746
- this._fireClick = true;
13747
-
13748
- // don't simulate click or track longpress if more than 1 touch
13749
- if (e.touches.length > 1) {
13750
- this._fireClick = false;
13751
- clearTimeout(this._holdTimeout);
13752
- return;
13753
- }
13754
-
13755
- var first = e.touches[0],
13756
- el = first.target;
14227
+ clearTimeout(this._holdTimeout);
14228
+ if (e.touches.length !== 1) { return; }
13757
14229
 
14230
+ var first = e.touches[0];
13758
14231
  this._startPos = this._newPos = new Point(first.clientX, first.clientY);
13759
14232
 
13760
- // if touching a link, highlight it
13761
- if (el.tagName && el.tagName.toLowerCase() === 'a') {
13762
- addClass(el, 'leaflet-active');
13763
- }
13764
-
13765
- // simulate long hold but setting a timeout
13766
14233
  this._holdTimeout = setTimeout(bind(function () {
13767
- if (this._isTapValid()) {
13768
- this._fireClick = false;
13769
- this._onUp();
13770
- this._simulateEvent('contextmenu', first);
13771
- }
13772
- }, this), 1000);
14234
+ this._cancel();
14235
+ if (!this._isTapValid()) { return; }
13773
14236
 
13774
- this._simulateEvent('mousedown', first);
14237
+ // prevent simulated mouse events https://w3c.github.io/touch-events/#mouse-events
14238
+ on(document, 'touchend', preventDefault);
14239
+ on(document, 'touchend touchcancel', this._cancelClickPrevent);
14240
+ this._simulateEvent('contextmenu', first);
14241
+ }, this), tapHoldDelay);
13775
14242
 
13776
- on(document, {
13777
- touchmove: this._onMove,
13778
- touchend: this._onUp
13779
- }, this);
14243
+ on(document, 'touchend touchcancel contextmenu', this._cancel, this);
14244
+ on(document, 'touchmove', this._onMove, this);
13780
14245
  },
13781
14246
 
13782
- _onUp: function (e) {
13783
- clearTimeout(this._holdTimeout);
13784
-
13785
- off(document, {
13786
- touchmove: this._onMove,
13787
- touchend: this._onUp
13788
- }, this);
13789
-
13790
- if (this._fireClick && e && e.changedTouches) {
13791
-
13792
- var first = e.changedTouches[0],
13793
- el = first.target;
13794
-
13795
- if (el && el.tagName && el.tagName.toLowerCase() === 'a') {
13796
- removeClass(el, 'leaflet-active');
13797
- }
13798
-
13799
- this._simulateEvent('mouseup', first);
13800
-
13801
- // simulate click if the touch didn't move too much
13802
- if (this._isTapValid()) {
13803
- this._simulateEvent('click', first);
13804
- }
13805
- }
14247
+ _cancelClickPrevent: function cancelClickPrevent() {
14248
+ off(document, 'touchend', preventDefault);
14249
+ off(document, 'touchend touchcancel', cancelClickPrevent);
13806
14250
  },
13807
14251
 
13808
- _isTapValid: function () {
13809
- return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
14252
+ _cancel: function () {
14253
+ clearTimeout(this._holdTimeout);
14254
+ off(document, 'touchend touchcancel contextmenu', this._cancel, this);
14255
+ off(document, 'touchmove', this._onMove, this);
13810
14256
  },
13811
14257
 
13812
14258
  _onMove: function (e) {
13813
14259
  var first = e.touches[0];
13814
14260
  this._newPos = new Point(first.clientX, first.clientY);
13815
- this._simulateEvent('mousemove', first);
14261
+ },
14262
+
14263
+ _isTapValid: function () {
14264
+ return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
13816
14265
  },
13817
14266
 
13818
14267
  _simulateEvent: function (type, e) {
13819
- var simulatedEvent = document.createEvent('MouseEvents');
14268
+ var simulatedEvent = new MouseEvent(type, {
14269
+ bubbles: true,
14270
+ cancelable: true,
14271
+ view: window,
14272
+ // detail: 1,
14273
+ screenX: e.screenX,
14274
+ screenY: e.screenY,
14275
+ clientX: e.clientX,
14276
+ clientY: e.clientY,
14277
+ // button: 2,
14278
+ // buttons: 2
14279
+ });
13820
14280
 
13821
14281
  simulatedEvent._simulated = true;
13822
- e.target._simulatedClick = true;
13823
-
13824
- simulatedEvent.initMouseEvent(
13825
- type, true, true, window, 1,
13826
- e.screenX, e.screenY,
13827
- e.clientX, e.clientY,
13828
- false, false, false, false, 0, null);
13829
14282
 
13830
14283
  e.target.dispatchEvent(simulatedEvent);
13831
14284
  }
13832
14285
  });
13833
14286
 
13834
14287
  // @section Handlers
13835
- // @property tap: Handler
13836
- // Mobile touch hacks (quick tap and touch hold) handler.
13837
- if (touch && (!pointer || safari)) {
13838
- Map.addInitHook('addHandler', 'tap', Tap);
13839
- }
14288
+ // @property tapHold: Handler
14289
+ // Long tap handler to simulate `contextmenu` event (useful in mobile Safari).
14290
+ Map.addInitHook('addHandler', 'tapHold', TapHold);
13840
14291
 
13841
14292
  /*
13842
14293
  * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.
@@ -13850,8 +14301,8 @@
13850
14301
  // Whether the map can be zoomed by touch-dragging with two fingers. If
13851
14302
  // passed `'center'`, it will zoom to the center of the view regardless of
13852
14303
  // where the touch events (fingers) were. Enabled for touch-capable web
13853
- // browsers except for old Androids.
13854
- touchZoom: touch && !android23,
14304
+ // browsers.
14305
+ touchZoom: Browser.touch,
13855
14306
 
13856
14307
  // @option bounceAtZoomLimits: Boolean = true
13857
14308
  // Set it to false if you don't want the map to zoom beyond min/max zoom
@@ -13892,7 +14343,7 @@
13892
14343
  map._stop();
13893
14344
 
13894
14345
  on(document, 'touchmove', this._onTouchMove, this);
13895
- on(document, 'touchend', this._onTouchEnd, this);
14346
+ on(document, 'touchend touchcancel', this._onTouchEnd, this);
13896
14347
 
13897
14348
  preventDefault(e);
13898
14349
  },
@@ -13930,7 +14381,7 @@
13930
14381
 
13931
14382
  cancelAnimFrame(this._animRequest);
13932
14383
 
13933
- var moveFn = bind(map._move, map, this._center, this._zoom, {pinch: true, round: false});
14384
+ var moveFn = bind(map._move, map, this._center, this._zoom, {pinch: true, round: false}, undefined);
13934
14385
  this._animRequest = requestAnimFrame(moveFn, this, true);
13935
14386
 
13936
14387
  preventDefault(e);
@@ -13946,7 +14397,7 @@
13946
14397
  cancelAnimFrame(this._animRequest);
13947
14398
 
13948
14399
  off(document, 'touchmove', this._onTouchMove, this);
13949
- off(document, 'touchend', this._onTouchEnd, this);
14400
+ off(document, 'touchend touchcancel', this._onTouchEnd, this);
13950
14401
 
13951
14402
  // Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.
13952
14403
  if (this._map.options.zoomAnimation) {
@@ -13967,96 +14418,95 @@
13967
14418
  Map.Drag = Drag;
13968
14419
  Map.Keyboard = Keyboard;
13969
14420
  Map.ScrollWheelZoom = ScrollWheelZoom;
13970
- Map.Tap = Tap;
14421
+ Map.TapHold = TapHold;
13971
14422
  Map.TouchZoom = TouchZoom;
13972
14423
 
13973
- exports.version = version;
13974
- exports.Control = Control;
13975
- exports.control = control;
14424
+ exports.Bounds = Bounds;
13976
14425
  exports.Browser = Browser;
13977
- exports.Evented = Evented;
13978
- exports.Mixin = Mixin;
13979
- exports.Util = Util;
14426
+ exports.CRS = CRS;
14427
+ exports.Canvas = Canvas;
14428
+ exports.Circle = Circle;
14429
+ exports.CircleMarker = CircleMarker;
13980
14430
  exports.Class = Class;
13981
- exports.Handler = Handler;
13982
- exports.extend = extend;
13983
- exports.bind = bind;
13984
- exports.stamp = stamp;
13985
- exports.setOptions = setOptions;
14431
+ exports.Control = Control;
14432
+ exports.DivIcon = DivIcon;
14433
+ exports.DivOverlay = DivOverlay;
13986
14434
  exports.DomEvent = DomEvent;
13987
14435
  exports.DomUtil = DomUtil;
13988
- exports.PosAnimation = PosAnimation;
13989
14436
  exports.Draggable = Draggable;
13990
- exports.LineUtil = LineUtil;
13991
- exports.PolyUtil = PolyUtil;
13992
- exports.Point = Point;
13993
- exports.point = toPoint;
13994
- exports.Bounds = Bounds;
13995
- exports.bounds = toBounds;
13996
- exports.Transformation = Transformation;
13997
- exports.transformation = toTransformation;
13998
- exports.Projection = index;
14437
+ exports.Evented = Evented;
14438
+ exports.FeatureGroup = FeatureGroup;
14439
+ exports.GeoJSON = GeoJSON;
14440
+ exports.GridLayer = GridLayer;
14441
+ exports.Handler = Handler;
14442
+ exports.Icon = Icon;
14443
+ exports.ImageOverlay = ImageOverlay;
13999
14444
  exports.LatLng = LatLng;
14000
- exports.latLng = toLatLng;
14001
14445
  exports.LatLngBounds = LatLngBounds;
14002
- exports.latLngBounds = toLatLngBounds;
14003
- exports.CRS = CRS;
14004
- exports.GeoJSON = GeoJSON;
14005
- exports.geoJSON = geoJSON;
14006
- exports.geoJson = geoJson;
14007
14446
  exports.Layer = Layer;
14008
14447
  exports.LayerGroup = LayerGroup;
14009
- exports.layerGroup = layerGroup;
14010
- exports.FeatureGroup = FeatureGroup;
14011
- exports.featureGroup = featureGroup;
14012
- exports.ImageOverlay = ImageOverlay;
14013
- exports.imageOverlay = imageOverlay;
14014
- exports.VideoOverlay = VideoOverlay;
14015
- exports.videoOverlay = videoOverlay;
14016
- exports.SVGOverlay = SVGOverlay;
14017
- exports.svgOverlay = svgOverlay;
14018
- exports.DivOverlay = DivOverlay;
14448
+ exports.LineUtil = LineUtil;
14449
+ exports.Map = Map;
14450
+ exports.Marker = Marker;
14451
+ exports.Mixin = Mixin;
14452
+ exports.Path = Path;
14453
+ exports.Point = Point;
14454
+ exports.PolyUtil = PolyUtil;
14455
+ exports.Polygon = Polygon;
14456
+ exports.Polyline = Polyline;
14019
14457
  exports.Popup = Popup;
14020
- exports.popup = popup;
14458
+ exports.PosAnimation = PosAnimation;
14459
+ exports.Projection = index;
14460
+ exports.Rectangle = Rectangle;
14461
+ exports.Renderer = Renderer;
14462
+ exports.SVG = SVG;
14463
+ exports.SVGOverlay = SVGOverlay;
14464
+ exports.TileLayer = TileLayer;
14021
14465
  exports.Tooltip = Tooltip;
14022
- exports.tooltip = tooltip;
14023
- exports.Icon = Icon;
14024
- exports.icon = icon;
14025
- exports.DivIcon = DivIcon;
14466
+ exports.Transformation = Transformation;
14467
+ exports.Util = Util;
14468
+ exports.VideoOverlay = VideoOverlay;
14469
+ exports.bind = bind;
14470
+ exports.bounds = toBounds;
14471
+ exports.canvas = canvas;
14472
+ exports.circle = circle;
14473
+ exports.circleMarker = circleMarker;
14474
+ exports.control = control;
14026
14475
  exports.divIcon = divIcon;
14027
- exports.Marker = Marker;
14028
- exports.marker = marker;
14029
- exports.TileLayer = TileLayer;
14030
- exports.tileLayer = tileLayer;
14031
- exports.GridLayer = GridLayer;
14476
+ exports.extend = extend;
14477
+ exports.featureGroup = featureGroup;
14478
+ exports.geoJSON = geoJSON;
14479
+ exports.geoJson = geoJson;
14032
14480
  exports.gridLayer = gridLayer;
14033
- exports.SVG = SVG;
14034
- exports.svg = svg$1;
14035
- exports.Renderer = Renderer;
14036
- exports.Canvas = Canvas;
14037
- exports.canvas = canvas$1;
14038
- exports.Path = Path;
14039
- exports.CircleMarker = CircleMarker;
14040
- exports.circleMarker = circleMarker;
14041
- exports.Circle = Circle;
14042
- exports.circle = circle;
14043
- exports.Polyline = Polyline;
14044
- exports.polyline = polyline;
14045
- exports.Polygon = Polygon;
14481
+ exports.icon = icon;
14482
+ exports.imageOverlay = imageOverlay;
14483
+ exports.latLng = toLatLng;
14484
+ exports.latLngBounds = toLatLngBounds;
14485
+ exports.layerGroup = layerGroup;
14486
+ exports.map = createMap;
14487
+ exports.marker = marker;
14488
+ exports.point = toPoint;
14046
14489
  exports.polygon = polygon;
14047
- exports.Rectangle = Rectangle;
14490
+ exports.polyline = polyline;
14491
+ exports.popup = popup;
14048
14492
  exports.rectangle = rectangle;
14049
- exports.Map = Map;
14050
- exports.map = createMap;
14493
+ exports.setOptions = setOptions;
14494
+ exports.stamp = stamp;
14495
+ exports.svg = svg;
14496
+ exports.svgOverlay = svgOverlay;
14497
+ exports.tileLayer = tileLayer;
14498
+ exports.tooltip = tooltip;
14499
+ exports.transformation = toTransformation;
14500
+ exports.version = version;
14501
+ exports.videoOverlay = videoOverlay;
14051
14502
 
14052
14503
  var oldL = window.L;
14053
14504
  exports.noConflict = function() {
14054
14505
  window.L = oldL;
14055
14506
  return this;
14056
14507
  }
14057
-
14058
14508
  // Always export us to window global (see #2364)
14059
14509
  window.L = exports;
14060
14510
 
14061
- })));
14511
+ }));
14062
14512
  //# sourceMappingURL=leaflet-src.js.map