merge stable

This commit is contained in:
Vladimir Agafonkin 2013-07-17 19:49:10 +03:00
commit 513998c3f3
28 changed files with 313 additions and 8972 deletions

View File

@ -1,3 +1,27 @@
---
language: node_js language: node_js
node_js: node_js:
- 0.10 - "0.10"
env:
global:
- "ARTIFACTS_S3_BUCKET=leaflet-cdn"
- secure: |-
LnvY/vWpmAIObabLrpu1mWYw1udllVpZJrrhzsn3traL+qU6yaGniQOn6u+l
iWSCuu7kXX3xv1GD7Fc6lTfQCg9F9dukWv9zlc4gFciyRpiUBuluuqtdV51A
5yqpLkMpX2PMG7vwrOYttVW0uDlUcwGjyHxWZvnBOXCnnHSpnbI=
- secure: |-
EQ4c2c8VklzFZRxKnizI0/VK0anHhlyc1Rv0vqkMj/YPKxmbWNfOlsOCN2gM
p+q8QzCG1Np9D1Kq9K0miYqHgZxgu4D/4Mwy04bh1UfyoUcDfB1tJmEtsKY/
8Bl46ZfhxbTG39b6Y315GuU+49QdFMEXhSqx/G7on1xC4aYLXLc=
before_script: >
test ${TRAVIS_BRANCH} = master ||
test ${TRAVIS_BRANCH} = stable &&
test ${TRAVIS_PULL_REQUEST} = false &&
gem install travis-artifacts || true
after_success: >
test ${TRAVIS_BRANCH} = master ||
test ${TRAVIS_BRANCH} = stable &&
test ${TRAVIS_PULL_REQUEST} = false &&
travis-artifacts upload --path dist --target-path build/${TRAVIS_BRANCH} &&
cd dist && zip -x .DS_Store -r leaflet-${TRAVIS_BRANCH}.zip . &&
travis-artifacts upload --path leaflet-${TRAVIS_BRANCH}.zip --target-path build

View File

@ -5,7 +5,42 @@ Leaflet Changelog
## 0.7-dev (master) ## 0.7-dev (master)
An in-progress version being developed on the master branch. No changes since latest stable release. An in-progress version being developed on the `master` branch. Includes all fixes from the `stable` branch.
* Added `TileLayer` `maxNativeZoom` option that allows displaying tile layers on zoom levels above their maximum by **upscaling tiles**. [#1802](https://github.com/Leaflet/Leaflet/issues/1802) [#1798](https://github.com/Leaflet/Leaflet/issues/1798)
## 0.6.3 (July 17, 2013)
### Regression fixes
* Fixed a regression where mouse interaction had incorrect coordinates in some map positioning cases (by [@scooterw](https://github.com/scooterw)). [#1826](https://github.com/Leaflet/Leaflet/issues/1826) [#1684](https://github.com/Leaflet/Leaflet/issues/1684) [#1745](https://github.com/Leaflet/Leaflet/issues/1745) [#1](https://github.com/Leaflet/Leaflet/issues/1)
* Fixed a regression that prevented the map from responding to drag on areas covered with `ImageOverlay` (by [@jfirebaugh](https://github.com/jfirebaugh)). [#1821](https://github.com/Leaflet/Leaflet/issues/1821)
* Fixed a regression where `layerremove` and `layeradd` were fired before the corresponding action finishes (by [@jfirebaugh](https://github.com/jfirebaugh)). [#1846](https://github.com/Leaflet/Leaflet/issues/1846)
* Fixed a regression with `worldCopyJump: true` breaking the map on small zoom levels (by [@danzel](https://github.com/danzel)). [#1831](https://github.com/Leaflet/Leaflet/issues/1831)
* Fixed a regression where `Marker` shadow didn't animate on zoom after using `setIcon`. [#1768](https://github.com/Leaflet/Leaflet/issues/1768)
* Fixed a regression where the map would stuck when trying to animate zoom before any tile layers are added to the map. [#1484](https://github.com/Leaflet/Leaflet/issues/1484) [#1845](https://github.com/Leaflet/Leaflet/issues/1845)
* Fixed a regression with the layers control and popups closing on inside click in IE < 9. [#1850](https://github.com/Leaflet/Leaflet/issues/1850)
* Fixed a regression where scrolled popup content woudln't scroll in FF (by [@jfirebaugh](https://github.com/jfirebaugh)).
### Bug fixes
* Fixed vector feature flickering on Safari Mac for screen < 2000px. [#902](https://github.com/Leaflet/Leaflet/issues/902)
* Fixed a bug where `GeoJSON` ignored non-feature geometries passed in an array. [#1840](https://github.com/Leaflet/Leaflet/issues/1840)
* Fixed a bug where `Map` `minZoom` and `maxZoom` didn't always override values derived from the added tile layers. [1848](https://github.com/Leaflet/Leaflet/issues/1848)
* Fixed a bug where `TileLayer.Canvas` wasn't immediately redrawn when `redraw` is called (by [@tofferrosen](https://github.com/tofferrosen)). [#1797](https://github.com/Leaflet/Leaflet/issues/1797) [#1817](https://github.com/Leaflet/Leaflet/issues/1817)
* Fixed a bug where `FeatureGroup` still fired `layerremove` event on `removeLayer` even if the given layer wan't present in the group (by (by [@danzel](https://github.com/danzel))). [#1847](https://github.com/Leaflet/Leaflet/issues/1847) [#1858](https://github.com/Leaflet/Leaflet/issues/1858)
* Fixed a bug where `Marker` `setOpacity` wasn't returning the marker (by [@freepius44](https://github.com/freepius44)). [#1851](https://github.com/Leaflet/Leaflet/issues/1851)
* Fixed a bug where removing the map element from the DOM before panning transition has finished could keep a setInterval loop running forever (by [@rutkovsky](https://github.com/rutkovsky)). [#1825](https://github.com/Leaflet/Leaflet/issues/1825) [#1856](https://github.com/Leaflet/Leaflet/issues/1856)
* Fixed mobile styles to apply to `leaflet-bar` elements.
### Improvements
* Added ability to pass zoom/pan animation options to `setMaxBounds` (by [@davidjb](http://git.io/djb)). [#1834](https://github.com/Leaflet/Leaflet/pull/1834)
* Added `MultiPolyline` and `MultiPolygon` `getLatLngs` method. [#1839](https://github.com/Leaflet/Leaflet/issues/1839)
### Dev Workflow improvements
* Leaflet builds (*.js files in the `dist` folder) were removed from the repo and are now done automatically on each commit for `master` and `stable` branches by [Travis CI](travis-ci.org/Leaflet/Leaflet). The download links are on the [Leafet download page](http://leafletjs.com/download.html).
## 0.6.2 (June 28, 2013) ## 0.6.2 (June 28, 2013)
@ -26,6 +61,7 @@ An in-progress version being developed on the master branch. No changes since la
* Moved polyline editing code into [Leaflet.draw](https://github.com/Leaflet/Leaflet.draw) plugin (where it fits much better along with all other editing and drawing handlers). The API remains the same. * Moved polyline editing code into [Leaflet.draw](https://github.com/Leaflet/Leaflet.draw) plugin (where it fits much better along with all other editing and drawing handlers). The API remains the same.
* Dropped support for environments that augment `Object.prototype` (luckily it's a thing of the past nowadays). * Dropped support for environments that augment `Object.prototype` (luckily it's a thing of the past nowadays).
* `Map` `invalidateSize` no longer fires `move` and `moveend` events if the map size didn't change. [#1819](https://github.com/Leaflet/Leaflet/issues/1819)
### Improvements ### Improvements
@ -127,22 +163,23 @@ An in-progress version being developed on the master branch. No changes since la
* Fixed a bug with `contextmenu` events on popups falling through to map (by [@snkashis](https://github.com/snkashis)). [#1730](https://github.com/Leaflet/Leaflet/issues/1730) [#1732](https://github.com/Leaflet/Leaflet/issues/1732) * Fixed a bug with `contextmenu` events on popups falling through to map (by [@snkashis](https://github.com/snkashis)). [#1730](https://github.com/Leaflet/Leaflet/issues/1730) [#1732](https://github.com/Leaflet/Leaflet/issues/1732)
* Fixed `404` tile loading errors when browsing the map off the world bounds. * Fixed `404` tile loading errors when browsing the map off the world bounds.
* Fixed shifted mouse events in some cases with map inside a relatively positioned parent (by [@scooterw](https://github.com/scooterw) and [@jec006](https://github.com/jec006)). [#1670](https://github.com/Leaflet/Leaflet/issues/1670) [#1684](https://github.com/Leaflet/Leaflet/issues/1684) [#1745](https://github.com/Leaflet/Leaflet/issues/1745) [#1744](https://github.com/Leaflet/Leaflet/issues/1744) * Fixed shifted mouse events in some cases with map inside a relatively positioned parent (by [@scooterw](https://github.com/scooterw) and [@jec006](https://github.com/jec006)). [#1670](https://github.com/Leaflet/Leaflet/issues/1670) [#1684](https://github.com/Leaflet/Leaflet/issues/1684) [#1745](https://github.com/Leaflet/Leaflet/issues/1745) [#1744](https://github.com/Leaflet/Leaflet/issues/1744)
* Fixed a bug where tile layer z-index order sometimes broke after view reset. [#1422](https://github.com/Leaflet/Leaflet/issues/1422)
#### Browser bugfixes #### Browser bugfixes
* Fixed a bug with undesirable page scrolling in Firefox 17+ when you zoom the map by scrolling (by [@jfirebaugh](https://github.com/jfirebaugh)). [#1789](https://github.com/Leaflet/Leaflet/issues/1789) [#1788](https://github.com/Leaflet/Leaflet/issues/1788) * Fixed a bug with undesirable page scrolling in Firefox 17+ when you zoom the map by scrolling (by [@jfirebaugh](https://github.com/jfirebaugh)). [#1789](https://github.com/Leaflet/Leaflet/issues/1789) [#1788](https://github.com/Leaflet/Leaflet/issues/1788)
* Fixed a bug in Android where click was triggered twice on one tap (by [@jerel](https://github.com/jerel) & [@mourner](https://github.com/mourner)). [#1227](https://github.com/Leaflet/Leaflet/pull/1227) [#1263](https://github.com/Leaflet/Leaflet/issues/1263) [#1785](https://github.com/Leaflet/Leaflet/issues/1785) [#1694](https://github.com/Leaflet/Leaflet/issues/1694)
* Fixed a bug in Android where click on a collapsed layers control would immediately select one of the layers (by [@danzel](https://github.com/danzel)). [#1784](https://github.com/Leaflet/Leaflet/issues/1784) [#1694](https://github.com/Leaflet/Leaflet/issues/1694)
* Fixed a bug where `TileLayer` opacity didn't work in IE 7-8 (by [@javisantana](https://github.com/javisantana) & [@danzel](https://gi
.com/danzel)). [#1084](https://github.com/Leaflet/Leaflet/issues/1084) [#1396](https://github.com/Leaflet/Leaflet/pull/1396) [#1371](https://github.com/Leaflet/Leaflet/issues/1371)
* Fixed a bug where mouse coordinates where shifted in Firefox if the map was inside a positioned block on a scrolled page (by [@joschka](https://github.com/joschka)). [#1365](https://github.com/Leaflet/Leaflet/pull/1365) [#1322](https://github.com/Leaflet/Leaflet/issues/1322) * Fixed a bug where mouse coordinates where shifted in Firefox if the map was inside a positioned block on a scrolled page (by [@joschka](https://github.com/joschka)). [#1365](https://github.com/Leaflet/Leaflet/pull/1365) [#1322](https://github.com/Leaflet/Leaflet/issues/1322)
* Fixed a bug where box zoom didn't work in some cases in Firefox 18+ (by [@fabriceds](https://github.com/fabriceds)). [#1405](https://github.com/Leaflet/Leaflet/pull/1405) * Fixed a bug where box zoom didn't work in some cases in Firefox 18+ (by [@fabriceds](https://github.com/fabriceds)). [#1405](https://github.com/Leaflet/Leaflet/pull/1405)
* Fixed a bug where tile layer z-index order sometimes broke after view reset. [#1422](https://github.com/Leaflet/Leaflet/issues/1422) * Fixed a bug where `TileLayer` opacity didn't work in IE 7-8 (by [@javisantana](https://github.com/javisantana) & [@danzel](https://gi
.com/danzel)). [#1084](https://github.com/Leaflet/Leaflet/issues/1084) [#1396](https://github.com/Leaflet/Leaflet/pull/1396) [#1371](https://github.com/Leaflet/Leaflet/issues/1371)
* Fixed Leaflet not working correctly in PhantomJS (by [@rassie](https://github.com/rassie)). [#1501](https://github.com/Leaflet/Leaflet/pull/1501) * Fixed Leaflet not working correctly in PhantomJS (by [@rassie](https://github.com/rassie)). [#1501](https://github.com/Leaflet/Leaflet/pull/1501)
#### Mobile bugfixes
* Fixed a bug with layers control on WinPhone8/IE10 Touch (by [@danzel](https://github.com/danzel)). [#1635](https://github.com/Leaflet/Leaflet/pull/1635) [#1539](https://github.com/Leaflet/Leaflet/issues/1539) * Fixed a bug with layers control on WinPhone8/IE10 Touch (by [@danzel](https://github.com/danzel)). [#1635](https://github.com/Leaflet/Leaflet/pull/1635) [#1539](https://github.com/Leaflet/Leaflet/issues/1539)
* Fixed a bug with click sometimes firing twice on WinPhone8/IE10 Touch (by [@danzel](https://github.com/danzel)). [#1694](https://github.com/Leaflet/Leaflet/issues/1694) * Fixed a bug with click sometimes firing twice on WinPhone8/IE10 Touch (by [@danzel](https://github.com/danzel)). [#1694](https://github.com/Leaflet/Leaflet/issues/1694)
* Fixed a bug in Android where click was triggered twice on one tap (by [@jerel](https://github.com/jerel) & [@mourner](https://github.com/mourner)). [#1227](https://github.com/Leaflet/Leaflet/pull/1227) [#1263](https://github.com/Leaflet/Leaflet/issues/1263) [#1785](https://github.com/Leaflet/Leaflet/issues/1785) [#1694](https://github.com/Leaflet/Leaflet/issues/1694)
#### Mobil * Fixed a bug in Android where click on a collapsed layers control would immediately select one of the layers (by [@danzel](https://github.com/danzel)). [#1784](https://github.com/Leaflet/Leaflet/issues/1784) [#1694](https://github.com/Leaflet/Leaflet/issues/1694)
#### API bugfixes #### API bugfixes

View File

@ -7,6 +7,7 @@ This guide lists a number of best practices for publishing a Leaflet plugin that
1. [Presentation](#presentation) 1. [Presentation](#presentation)
- [Repository](#repository) - [Repository](#repository)
- [Name](#name)
- [Demo](#demo) - [Demo](#demo)
- [Readme](#readme) - [Readme](#readme)
- [License](#license) - [License](#license)
@ -24,6 +25,12 @@ If you create a collection of plugins for different uses,
don't put them in one repo &mdash; don't put them in one repo &mdash;
it's usually easier to work with small, self-contained plugins in individual repositories. it's usually easier to work with small, self-contained plugins in individual repositories.
### Name
Most existing plugins follow the convention of naming plugins (and repos) like this: `Leaflet.MyPluginName`.
You can use other forms (e.g. "leaflet-my-plugin-name"),
just make sure to include the word "Leaflet" in the name so that it's obvious that it's a Leaflet plugin.
### Demo ### Demo
The most essential thing to do when publishing a plugin is to include a demo that showcases what the plugin does &mdash; The most essential thing to do when publishing a plugin is to include a demo that showcases what the plugin does &mdash;
@ -53,7 +60,7 @@ At a minimum it should contain the following items:
Every open source repository should include a license. Every open source repository should include a license.
If you don't know what open source license to choose for your code, If you don't know what open source license to choose for your code,
[MIT License](http://opensource.org/licenses/MIT) and [BSD 2-Clause License](http://opensource.org/licenses/BSD-2-Clause) are both good choices. [MIT License](http://opensource.org/licenses/MIT) and [BSD 2-Clause License](http://opensource.org/licenses/BSD-2-Clause) are both good choices.
You can either put it in the repo as a `LICENSE` file or just link to the license from the Readme. You can either put it in the repo as a `LICENSE` file or just link to the license from the Readme.
## Code ## Code
@ -64,20 +71,21 @@ Keep the file structure clean and simple,
don't pile up lots of files in one place &mdash; don't pile up lots of files in one place &mdash;
make it easy for a new person to find their way in your repo. make it easy for a new person to find their way in your repo.
A barebones repo for a simple plugin would like this: A barebones repo for a simple plugin would look like this:
``` ```
my-plugin.js my-plugin.js
README.md README.md
``` ```
An example of a file structure for a more sophisticated plugin: An example of a more sophisticated plugin file structure:
``` ```
/src JS source files /src - JS source files
/dist minified plugin JS, CSS, images /dist - minified plugin JS, CSS, images
/spec test files /spec - test files
/examples HTML examples of plugin usage /lib - any external libraries/plugins if necessary
/examples - HTML examples of plugin usage
README.md README.md
LICENSE LICENSE
package.json package.json
@ -94,15 +102,16 @@ and putting a space after the `function` keyword.
### Plugin API ### Plugin API
Never expose global variables in your plugin. Never expose global variables in your plugin.<br>
If you have a new class, put it directly in the `L` namespace (`L.MyPlugin`). If you have a new class, put it directly in the `L` namespace (`L.MyPlugin`).<br>
If you inherit one of the existing classes, make it a sub-property (`L.TileLayer.Banana`). If you inherit one of the existing classes, make it a sub-property (`L.TileLayer.Banana`).<br>
If you want to add new methods to existing Leaflet classes, you can do it like this: `L.Marker.include({myPlugin: …})`. If you want to add new methods to existing Leaflet classes, you can do it like this: `L.Marker.include({myPlugin: …})`.
Function, method and property names should be in `camelCase`. Function, method and property names should be in `camelCase`.<br>
Class names should be in `CapitalizedCamelCase`. Class names should be in `CapitalizedCamelCase`.
If you have a lot of arguments in your function, consider accepting an options object instead (putting default values where possible so that users don't need specify all of them): If you have a lot of arguments in your function, consider accepting an options object instead
(putting default values where possible so that users don't need specify all of them):
```js ```js
// bad // bad
@ -110,7 +119,7 @@ marker.myPlugin('bla', 'foo', null, {}, 5, 0);
// good // good
marker.myPlugin('bla', { marker.myPlugin('bla', {
optionOne: 'foo', optionOne: 'foo',
optionThree: 5 optionThree: 5
}); });
``` ```

View File

@ -2,7 +2,7 @@
Leaflet is a modern open-source JavaScript library for **mobile-friendly interactive maps**. Leaflet is a modern open-source JavaScript library for **mobile-friendly interactive maps**.
It is developed by [Vladimir Agafonkin][] with a team of dedicated [contributors][]. It is developed by [Vladimir Agafonkin][] with a team of dedicated [contributors][].
Weighing just about 27 KB of gzipped JS code, it has all the [features][] most developers ever need for online maps. Weighing just about 30 KB of gzipped JS code, it has all the [features][] most developers ever need for online maps.
Leaflet is designed with *simplicity*, *performance* and *usability* in mind. Leaflet is designed with *simplicity*, *performance* and *usability* in mind.
It works efficiently across all major desktop and mobile platforms out of the box, It works efficiently across all major desktop and mobile platforms out of the box,
@ -17,6 +17,9 @@ We're happy to meet new contributors.
If you want to **get involved** with Leaflet development, check out the [contribution guide][contribute]. If you want to **get involved** with Leaflet development, check out the [contribution guide][contribute].
Let's make the best open-source library for maps that can possibly exist! Let's make the best open-source library for maps that can possibly exist!
P.S. If you're looking for **Leaflet downloads** (including the built master version),
check out the [Leaflet Download Page][].
[![Build Status](https://travis-ci.org/Leaflet/Leaflet.png?branch=master)](https://travis-ci.org/Leaflet/Leaflet) [![Build Status](https://travis-ci.org/Leaflet/Leaflet.png?branch=master)](https://travis-ci.org/Leaflet/Leaflet)
[Vladimir Agafonkin]: http://agafonkin.com/en [Vladimir Agafonkin]: http://agafonkin.com/en
@ -28,3 +31,4 @@ Let's make the best open-source library for maps that can possibly exist!
[hosted on GitHub]: http://github.com/Leaflet/Leaflet [hosted on GitHub]: http://github.com/Leaflet/Leaflet
[contribute]: https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md "A guide to contributing to Leaflet" [contribute]: https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md "A guide to contributing to Leaflet"
[official website]: http://leafletjs.com [official website]: http://leafletjs.com
[Leaflet Download Page]: http://leafletjs.com/download.html

View File

@ -30,7 +30,13 @@
var map = new L.Map('map', {center: latlng, zoom: 15, layers: [cloudmade]}); var map = new L.Map('map', {center: latlng, zoom: 15, layers: [cloudmade]});
var s = '';
for (var i = 0; i < 100; i++) s += 'Test<br>';
var popup = L.popup({maxHeight: 100})
.setContent(s)
.setLatLng(latlng)
.openOn(map);
</script> </script>
</body> </body>
</html> </html>

8864
dist/leaflet-src.js vendored

File diff suppressed because it is too large Load Diff

4
dist/leaflet.css vendored
View File

@ -378,11 +378,11 @@
.leaflet-touch .leaflet-control-attribution, .leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers, .leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-control-zoom { .leaflet-touch .leaflet-bar {
box-shadow: none; box-shadow: none;
} }
.leaflet-touch .leaflet-control-layers, .leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-control-zoom { .leaflet-touch .leaflet-bar {
border: 4px solid rgba(0,0,0,0.3); border: 4px solid rgba(0,0,0,0.3);
} }

9
dist/leaflet.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "leaflet", "name": "leaflet",
"version": "0.6.2", "version": "0.6.3",
"description": "JavaScript library for mobile-friendly interactive maps", "description": "JavaScript library for mobile-friendly interactive maps",
"devDependencies": { "devDependencies": {
"jshint": "~2.1.4", "jshint": "~2.1.4",

View File

@ -0,0 +1,27 @@
describe('PosAnimation', function() {
var el;
beforeEach(function() {
el = document.createElement('div');
this.subject = new L.PosAnimation();
this.subject._el = el;
});
describe('#_onStep', function() {
it("sets element position and fires step event if it is able to get current position", function() {
var point = new L.Point(5, 5, true);
sinon.stub(this.subject, '_getPos').returns(point);
this.subject.fire = sinon.stub();
this.subject._onStep();
expect(this.subject.fire.withArgs('step').calledOnce).to.be(true);
expect(this.subject._el._leaflet_pos).to.be(point);
});
it('stops transition if a position returned', function() {
sinon.stub(this.subject, '_onTransitionEnd');
sinon.stub(this.subject, '_getPos').returns(undefined);
this.subject._onStep();
expect(this.subject._onTransitionEnd.calledOnce).to.be(true);
});
});
});

View File

@ -1,9 +1,12 @@
describe('CircleMarker', function () { describe('FeatureGroup', function () {
var map;
beforeEach(function () {
map = L.map(document.createElement('div'));
map.setView([0, 0], 1);
});
describe("#_propagateEvent", function () { describe("#_propagateEvent", function () {
var map, marker; var marker;
beforeEach(function () { beforeEach(function () {
map = L.map(document.createElement('div'));
map.setView([0, 0], 1);
marker = L.marker([0, 0]); marker = L.marker([0, 0]);
}); });
describe("when a Marker is added to multiple FeatureGroups ", function () { describe("when a Marker is added to multiple FeatureGroups ", function () {
@ -33,4 +36,38 @@
}); });
}); });
}); });
describe('addLayer', function () {
it('adds the layer', function () {
var fg = L.featureGroup(),
marker = L.marker([0, 0]);
expect(fg.hasLayer(marker)).to.be(false);
fg.addLayer(marker);
expect(fg.hasLayer(marker)).to.be(true);
});
});
describe('removeLayer', function () {
it('removes the layer passed to it', function () {
var fg = L.featureGroup(),
marker = L.marker([0, 0]);
fg.addLayer(marker);
expect(fg.hasLayer(marker)).to.be(true);
fg.removeLayer(marker);
expect(fg.hasLayer(marker)).to.be(false);
});
it('removes the layer passed to it by id', function () {
var fg = L.featureGroup(),
marker = L.marker([0, 0]);
fg.addLayer(marker);
expect(fg.hasLayer(marker)).to.be(true);
fg.removeLayer(marker._leaflet_id);
expect(fg.hasLayer(marker)).to.be(false);
});
});
}); });

View File

@ -13,10 +13,11 @@ describe('TileLayer', function () {
minZoom = 5; minZoom = 5;
map.setView([0, 0], 1); map.setView([0, 0], 1);
L.tileLayer(tileUrl, { L.tileLayer(tileUrl, {
maxZoom: maxZoom, maxZoom: maxZoom,
minZoom: minZoom minZoom: minZoom
}).addTo(map); }).addTo(map);
expect(map.getMaxZoom()).to.be(maxZoom); expect(map.getMaxZoom()).to.be(maxZoom);
expect(map.getMinZoom()).to.be(minZoom); expect(map.getMinZoom()).to.be(minZoom);
}); });

View File

@ -122,12 +122,15 @@ describe("Map", function () {
describe("#getMinZoom and #getMaxZoom", function () { describe("#getMinZoom and #getMaxZoom", function () {
it("minZoom and maxZoom options overrides any minZoom and maxZoom set on layers", function () { it("minZoom and maxZoom options overrides any minZoom and maxZoom set on layers", function () {
var c = document.createElement('div'),
map = L.map(c, { minZoom: 5, maxZoom: 10 }); var map = L.map(document.createElement('div'), {minZoom: 2, maxZoom: 20});
L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
L.tileLayer("{z}{x}{y}", { minZoom:5, maxZoom: 15 }).addTo(map); L.tileLayer("{z}{x}{y}", {minZoom: 4, maxZoom: 10}).addTo(map);
expect(map.getMinZoom()).to.be(5); L.tileLayer("{z}{x}{y}", {minZoom: 6, maxZoom: 17}).addTo(map);
expect(map.getMaxZoom()).to.be(10); L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 22}).addTo(map);
expect(map.getMinZoom()).to.be(2);
expect(map.getMaxZoom()).to.be(20);
}); });
}); });
@ -184,6 +187,16 @@ describe("Map", function () {
expect(spy.called).not.to.be.ok(); expect(spy.called).not.to.be.ok();
}); });
it("adds the layer before firing layeradd", function (done) {
var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() };
map.on('layeradd', function() {
expect(map.hasLayer(layer)).to.be.ok();
done();
});
map.setView([0, 0], 0);
map.addLayer(layer);
});
describe("When the first layer is added to a map", function () { describe("When the first layer is added to a map", function () {
it("fires a zoomlevelschange event", function () { it("fires a zoomlevelschange event", function () {
var spy = sinon.spy(); var spy = sinon.spy();
@ -270,6 +283,17 @@ describe("Map", function () {
expect(spy.called).not.to.be.ok(); expect(spy.called).not.to.be.ok();
}); });
it("removes the layer before firing layerremove", function (done) {
var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() };
map.on('layerremove', function() {
expect(map.hasLayer(layer)).not.to.be.ok();
done();
});
map.setView([0, 0], 0);
map.addLayer(layer);
map.removeLayer(layer);
});
describe("when the last tile layer on a map is removed", function () { describe("when the last tile layer on a map is removed", function () {
it("fires a zoomlevelschange event", function () { it("fires a zoomlevelschange event", function () {
map.whenReady(function(){ map.whenReady(function(){

View File

@ -2,7 +2,7 @@
var oldL = window.L, var oldL = window.L,
L = {}; L = {};
L.version = '0.6.2'; L.version = '0.6.3';
// define Leaflet for Node module pattern loaders, including Browserify // define Leaflet for Node module pattern loaders, including Browserify
if (typeof module === 'object' && typeof module.exports === 'object') { if (typeof module === 'object' && typeof module.exports === 'object') {

View File

@ -132,13 +132,30 @@ L.DomEvent = {
getMousePosition: function (e, container) { getMousePosition: function (e, container) {
var body = document.body, var ie7 = L.Browser.ie7,
body = document.body,
docEl = document.documentElement, docEl = document.documentElement,
x = e.pageX ? e.pageX : e.clientX + body.scrollLeft + docEl.scrollLeft, x = e.pageX ? e.pageX - body.scrollLeft - docEl.scrollLeft: e.clientX,
y = e.pageY ? e.pageY : e.clientY + body.scrollTop + docEl.scrollTop, y = e.pageY ? e.pageY - body.scrollTop - docEl.scrollTop: e.clientY,
pos = new L.Point(x, y); pos = new L.Point(x, y),
rect = container.getBoundingClientRect(),
left = rect.left - container.clientLeft,
top = rect.top - container.clientTop;
return (container ? pos._subtract(L.DomUtil.getViewportOffset(container)) : pos); // webkit (and ie <= 7) handles RTL scrollLeft different to everyone else
// https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/style/bidi.js
if (!L.DomUtil.documentIsLtr() && (L.Browser.webkit || ie7)) {
left += container.scrollWidth - container.clientWidth;
// ie7 shows the scrollbar by default and provides clientWidth counting it, so we
// need to add it back in if it is visible; scrollbar is on the left as we are RTL
if (ie7 && L.DomUtil.getStyle(container, 'overflow-y') !== 'hidden' &&
L.DomUtil.getStyle(container, 'overflow') !== 'hidden') {
left += 17;
}
}
return pos._subtract(new L.Point(left, top));
}, },
getWheelDelta: function (e) { getWheelDelta: function (e) {
@ -154,10 +171,18 @@ L.DomEvent = {
return delta; return delta;
}, },
_fakeStop: function stop(e) { _skipEvents: {},
// fakes stopPropagation by setting a special event flag checked in Map mouse events handler
// jshint camelcase: false _fakeStop: function (e) {
e._leaflet_stop = true; // fakes stopPropagation by setting a special event flag, checked/reset with L.DomEvent._skipped(e)
L.DomEvent._skipEvents[e.type] = true;
},
_skipped: function (e) {
var skipped = this._skipEvents[e.type];
// reset when checking, as it's only used in map container and propagates outside of the map
this._skipEvents[e.type] = false;
return skipped;
}, },
// check if element really left/entered the event target (for mouseenter/mouseleave) // check if element really left/entered the event target (for mouseenter/mouseleave)

View File

@ -241,46 +241,30 @@ L.DomUtil.TRANSITION_END =
var userSelectProperty = L.DomUtil.testProp( var userSelectProperty = L.DomUtil.testProp(
['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']); ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
var userDragProperty = L.DomUtil.testProp(
['userDrag', 'WebkitUserDrag', 'OUserDrag', 'MozUserDrag', 'msUserDrag']);
L.extend(L.DomUtil, { L.extend(L.DomUtil, {
disableTextSelection: function () { disableTextSelection: function () {
L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault);
if (userSelectProperty) { if (userSelectProperty) {
var style = document.documentElement.style; var style = document.documentElement.style;
this._userSelect = style[userSelectProperty]; this._userSelect = style[userSelectProperty];
style[userSelectProperty] = 'none'; style[userSelectProperty] = 'none';
} else {
L.DomEvent.on(window, 'selectstart', L.DomEvent.stop);
} }
}, },
enableTextSelection: function () { enableTextSelection: function () {
L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault);
if (userSelectProperty) { if (userSelectProperty) {
document.documentElement.style[userSelectProperty] = this._userSelect; document.documentElement.style[userSelectProperty] = this._userSelect;
delete this._userSelect; delete this._userSelect;
} else {
L.DomEvent.off(window, 'selectstart', L.DomEvent.stop);
} }
}, },
disableImageDrag: function () { disableImageDrag: function () {
if (userDragProperty) { L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault);
var style = document.documentElement.style;
this._userDrag = style[userDragProperty];
style[userDragProperty] = 'none';
} else {
L.DomEvent.on(window, 'dragstart', L.DomEvent.stop);
}
}, },
enableImageDrag: function () { enableImageDrag: function () {
if (userDragProperty) { L.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault);
document.documentElement.style[userDragProperty] = this._userDrag;
delete this._userDrag;
} else {
L.DomEvent.off(window, 'dragstart', L.DomEvent.stop);
}
} }
}); });
})(); })();

View File

@ -39,9 +39,14 @@ L.PosAnimation = L.Class.extend({
}, },
_onStep: function () { _onStep: function () {
var stepPos = this._getPos();
if (!stepPos) {
this._onTransitionEnd();
return;
}
// jshint camelcase: false // jshint camelcase: false
// make L.DomUtil.getPosition return intermediate position value during animation // make L.DomUtil.getPosition return intermediate position value during animation
this._el._leaflet_pos = this._getPos(); this._el._leaflet_pos = stepPos;
this.fire('step'); this.fire('step');
}, },
@ -58,8 +63,9 @@ L.PosAnimation = L.Class.extend({
if (L.Browser.any3d) { if (L.Browser.any3d) {
matches = style[L.DomUtil.TRANSFORM].match(this._transformRe); matches = style[L.DomUtil.TRANSFORM].match(this._transformRe);
left = matches ? parseFloat(matches[1]) : 0; if (!matches) { return; }
top = matches ? parseFloat(matches[2]) : 0; left = parseFloat(matches[1]);
top = parseFloat(matches[2]);
} else { } else {
left = parseFloat(style.left); left = parseFloat(style.left);
top = parseFloat(style.top); top = parseFloat(style.top);

View File

@ -27,6 +27,9 @@ L.FeatureGroup = L.LayerGroup.extend({
}, },
removeLayer: function (layer) { removeLayer: function (layer) {
if (!this.hasLayer(layer)) {
return this;
}
if (layer in this._layers) { if (layer in this._layers) {
layer = this._layers[layer]; layer = this._layers[layer];
} }

View File

@ -16,12 +16,13 @@ L.GeoJSON = L.FeatureGroup.extend({
addData: function (geojson) { addData: function (geojson) {
var features = L.Util.isArray(geojson) ? geojson : geojson.features, var features = L.Util.isArray(geojson) ? geojson : geojson.features,
i, len; i, len, feature;
if (features) { if (features) {
for (i = 0, len = features.length; i < len; i++) { for (i = 0, len = features.length; i < len; i++) {
// Only add this if geometry or geometries are set and not null // Only add this if geometry or geometries are set and not null
if (features[i].geometries || features[i].geometry || features[i].features) { feature = features[i];
if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
this.addData(features[i]); this.addData(features[i]);
} }
} }

View File

@ -153,6 +153,7 @@ L.Popup = L.Class.extend({
this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper); this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper);
L.DomEvent.on(this._contentNode, 'mousewheel', L.DomEvent.stopPropagation); L.DomEvent.on(this._contentNode, 'mousewheel', L.DomEvent.stopPropagation);
L.DomEvent.on(this._contentNode, 'MozMousePixelScroll', L.DomEvent.stopPropagation);
L.DomEvent.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation); L.DomEvent.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation);
this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container); this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container);
this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer); this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer);

View File

@ -142,10 +142,10 @@ L.Marker = L.Class.extend({
if (newShadow !== this._shadow) { if (newShadow !== this._shadow) {
this._removeShadow(); this._removeShadow();
addShadow = true; addShadow = true;
}
if (newShadow) { if (newShadow) {
L.DomUtil.addClass(newShadow, classToAdd); L.DomUtil.addClass(newShadow, classToAdd);
}
} }
this._shadow = newShadow; this._shadow = newShadow;
@ -283,6 +283,8 @@ L.Marker = L.Class.extend({
if (this._map) { if (this._map) {
this._updateOpacity(); this._updateOpacity();
} }
return this;
}, },
_updateOpacity: function () { _updateOpacity: function () {

View File

@ -13,6 +13,11 @@ L.TileLayer.Canvas = L.TileLayer.extend({
}, },
redraw: function () { redraw: function () {
if (this._map) {
this._reset({hard: true});
this._update();
}
for (var i in this._tiles) { for (var i in this._tiles) {
this._redrawTile(this._tiles[i]); this._redrawTile(this._tiles[i]);
} }

View File

@ -30,6 +30,16 @@
} }
return this; return this;
},
getLatLngs: function () {
var latlngs = [];
this.eachLayer(function (layer) {
latlngs.push(layer.getLatLngs());
});
return latlngs;
} }
}); });
} }

View File

@ -9,9 +9,11 @@ L.Path = L.Class.extend({
// how much to extend the clip area around the map view // how much to extend the clip area around the map view
// (relative to its size, e.g. 0.5 is half the screen in each direction) // (relative to its size, e.g. 0.5 is half the screen in each direction)
// set it so that SVG element doesn't exceed 1280px (vectors flicker on dragend if it is) // set it so that SVG element doesn't exceed 1280px (vectors flicker on dragend if it is)
CLIP_PADDING: L.Browser.mobile ? CLIP_PADDING: (function () {
Math.max(0, Math.min(0.5, var max = L.Browser.mobile ? 1280 : 2000,
(1280 / Math.max(window.innerWidth, window.innerHeight) - 1) / 2)) : 0.5 target = (max / Math.max(window.outerWidth, window.outerHeight) - 1) / 2;
return Math.max(0, Math.min(0.5, target));
})()
}, },
options: { options: {

View File

@ -114,7 +114,7 @@ L.Map = L.Class.extend({
return this.fire('moveend'); return this.fire('moveend');
}, },
setMaxBounds: function (bounds) { setMaxBounds: function (bounds, options) {
bounds = L.latLngBounds(bounds); bounds = L.latLngBounds(bounds);
this.options.maxBounds = bounds; this.options.maxBounds = bounds;
@ -131,7 +131,7 @@ L.Map = L.Class.extend({
if (this._loaded) { if (this._loaded) {
if (this._zoom < minZoom) { if (this._zoom < minZoom) {
this.setView(bounds.getCenter(), minZoom); this.setView(bounds.getCenter(), minZoom, options);
} else { } else {
this.panInsideBounds(bounds); this.panInsideBounds(bounds);
} }
@ -209,10 +209,14 @@ L.Map = L.Class.extend({
if (this._loaded) { if (this._loaded) {
layer.onRemove(this); layer.onRemove(this);
this.fire('layerremove', {layer: layer});
} }
delete this._layers[id]; delete this._layers[id];
if (this._loaded) {
this.fire('layerremove', {layer: layer});
}
if (this._zoomBoundLayers[id]) { if (this._zoomBoundLayers[id]) {
delete this._zoomBoundLayers[id]; delete this._zoomBoundLayers[id];
this._updateZoomLevels(); this._updateZoomLevels();
@ -341,18 +345,15 @@ L.Map = L.Class.extend({
}, },
getMinZoom: function () { getMinZoom: function () {
var z1 = this.options.minZoom || 0, var z1 = this._layersMinZoom === undefined ? -Infinity : this._layersMinZoom,
z2 = this._layersMinZoom || 0, z2 = this._boundsMinZoom === undefined ? -Infinity : this._boundsMinZoom;
z3 = this._boundsMinZoom || 0; return this.options.minZoom === undefined ? Math.max(z1, z2) : this.options.minZoom;
return Math.max(z1, z2, z3);
}, },
getMaxZoom: function () { getMaxZoom: function () {
var z1 = this.options.maxZoom === undefined ? Infinity : this.options.maxZoom, return this.options.maxZoom === undefined ?
z2 = this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom; (this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
this.options.maxZoom;
return Math.min(z1, z2);
}, },
getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
@ -672,16 +673,15 @@ L.Map = L.Class.extend({
}, },
_onMouseClick: function (e) { _onMouseClick: function (e) {
// jshint camelcase: false if (!this._loaded || (!e._simulated && this.dragging && this.dragging.moved()) ||
if (!this._loaded || (!e._simulated && this.dragging && this.dragging.moved()) || e._leaflet_stop) { return; } L.DomEvent._skipped(e)) { return; }
this.fire('preclick'); this.fire('preclick');
this._fireMouseEvent(e); this._fireMouseEvent(e);
}, },
_fireMouseEvent: function (e) { _fireMouseEvent: function (e) {
// jshint camelcase: false if (!this._loaded || L.DomEvent._skipped(e)) { return; }
if (!this._loaded || e._leaflet_stop) { return; }
var type = e.type; var type = e.type;

View File

@ -30,6 +30,10 @@ L.Map.include(!L.DomUtil.TRANSITION ? {} : {
} }
}, },
_nothingToAnimate: function () {
return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
},
_tryAnimatedZoom: function (center, zoom, options) { _tryAnimatedZoom: function (center, zoom, options) {
if (this._animatingZoom) { return true; } if (this._animatingZoom) { return true; }
@ -37,7 +41,7 @@ L.Map.include(!L.DomUtil.TRANSITION ? {} : {
options = options || {}; options = options || {};
// don't animate if disabled, not supported or zoom difference is too large // don't animate if disabled, not supported or zoom difference is too large
if (!this._zoomAnimated || options.animate === false || if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; } Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
// offset is the pixel coords of the zoom origin relative to the current center // offset is the pixel coords of the zoom origin relative to the current center

View File

@ -83,7 +83,7 @@ L.Map.include({
var data = { var data = {
latlng: latlng, latlng: latlng,
bounds: bounds, bounds: bounds
}; };
for (var i in pos.coords) { for (var i in pos.coords) {

View File

@ -31,6 +31,8 @@ L.Map.Drag = L.Handler.extend({
if (map.options.worldCopyJump) { if (map.options.worldCopyJump) {
this._draggable.on('predrag', this._onPreDrag, this); this._draggable.on('predrag', this._onPreDrag, this);
map.on('viewreset', this._onViewReset, this); map.on('viewreset', this._onViewReset, this);
this._onViewReset();
} }
} }
this._draggable.enable(); this._draggable.enable();