diff --git a/debug/geojson/group.html b/debug/geojson/group.html
new file mode 100644
index 000000000..cbd58007e
--- /dev/null
+++ b/debug/geojson/group.html
@@ -0,0 +1,56 @@
+
+
+
+ Leaflet debug page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/debug/leaflet-include.js b/debug/leaflet-include.js
index abda8706d..7d6029eeb 100644
--- a/debug/leaflet-include.js
+++ b/debug/leaflet-include.js
@@ -36,6 +36,9 @@
'geo/crs/CRS.EPSG4326.js',
'geo/crs/CRS.EPSG3395.js',
+ 'layer/LayerGroup.js',
+ 'layer/FeatureGroup.js',
+
'layer/tile/TileLayer.js',
'layer/tile/TileLayer.WMS.js',
'layer/tile/TileLayer.Canvas.js',
diff --git a/src/layer/FeatureGroup.js b/src/layer/FeatureGroup.js
new file mode 100644
index 000000000..4cd9efec2
--- /dev/null
+++ b/src/layer/FeatureGroup.js
@@ -0,0 +1,34 @@
+/*
+ * L.FeatureGroup extends L.LayerGroup by introducing mouse events and bindPopup method shared between a group of layers.
+ */
+
+L.FeatureGroup = L.LayerGroup.extend({
+ includes: L.Mixin.Events,
+
+ addLayer: function(layer) {
+ this._initEvents(layer);
+ L.LayerGroup.prototype.addLayer.call(this, layer);
+ },
+
+ bindPopup: function(content) {
+ for (var i in this._layers) {
+ if (this._layers.hasOwnProperty(i) && this._layers[i].bindPopup) {
+ this._layers[i].bindPopup(content);
+ }
+ }
+ },
+
+ _events: ['click', 'dblclick', 'mouseover', 'mouseout'],
+
+ _initEvents: function(layer) {
+ for (var i = 0, len = this._events.length; i < len; i++) {
+ layer.on(this._events[i], this._propagateEvent, this);
+ }
+ },
+
+ _propagateEvent: function(e) {
+ e.layer = e.target;
+ e.target = this;
+ this.fire(e.type, e);
+ }
+});
\ No newline at end of file
diff --git a/src/layer/LayerGroup.js b/src/layer/LayerGroup.js
new file mode 100644
index 000000000..58940d40f
--- /dev/null
+++ b/src/layer/LayerGroup.js
@@ -0,0 +1,58 @@
+/*
+ * L.LayerGroup is a class to combine several layers so you can manipulate the group (e.g. add/remove it) as one layer.
+ */
+
+L.LayerGroup = L.Class.extend({
+ initialize: function(layers) {
+ this._layers = {};
+
+ if (layers) {
+ for (var i = 0, len = layers.length; i < len; i++) {
+ this.addLayer(layers[i]);
+ }
+ }
+ },
+
+ addLayer: function(layer) {
+ var id = L.Util.stamp(layer);
+ this._layers[id] = layer;
+
+ if (this._map) {
+ this._map.addLayer(layer);
+ }
+ return this;
+ },
+
+ removeLayer: function(layer) {
+ var id = L.Util.stamp(layer);
+ delete this._layers[id];
+
+ if (this._map) {
+ this._map.removeLayer(layer);
+ }
+ return this;
+ },
+
+ clearLayers: function() {
+ this._iterateLayers(this.removeLayer, this);
+ return this;
+ },
+
+ onAdd: function(map) {
+ this._map = map;
+ this._iterateLayers(map.addLayer, map);
+ },
+
+ onRemove: function(map) {
+ this._iterateLayers(map.removeLayer, map);
+ delete this._map;
+ },
+
+ _iterateLayers: function(method, context) {
+ for (var i in this._layers) {
+ if (this._layers.hasOwnProperty(i)) {
+ method.call(context, this._layers[i]);
+ }
+ }
+ }
+});
\ No newline at end of file