diff --git a/RELEASING.md b/RELEASING.md
index ee71752d7c..98f5cf45f5 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -13,7 +13,7 @@
- Create a new branch to prepare the release:
```
-git flow release start 3.15.3
+git flow release start 3.15.4
```
- Build CartoDB.js files, choosing the new version:
@@ -25,7 +25,7 @@ grunt release
- Update the NEWS file and commit the changes. Take into account that new CartoDB.js version will be replaced in ```API.md```, ```RELEASING.md```, ```README.md```, ```package.json```, ```cartodb.js``` and ```examples``` files.
```
-git commit -am "Files changed for version 3.15.3"
+git commit -am "Files changed for version 3.15.4"
```
- Release it.
@@ -36,8 +36,8 @@ grunt publish
- Check if those files have been updated in the CDN:
```
-http://libs.cartocdn.com.s3.amazonaws.com/cartodb.js/v3/3.15.3/cartodb.js
-http://libs.cartocdn.com/cartodb.js/v3/3.15.3/cartodb.js
+http://libs.cartocdn.com.s3.amazonaws.com/cartodb.js/v3/3.15.4/cartodb.js
+http://libs.cartocdn.com/cartodb.js/v3/3.15.4/cartodb.js
http://libs.cartocdn.com.s3.amazonaws.com/cartodb.js/v3/3.13/cartodb.js
http://libs.cartocdn.com/cartodb.js/v3/3.13/cartodb.js
```
@@ -46,7 +46,7 @@ http://libs.cartocdn.com/cartodb.js/v3/3.13/cartodb.js
- And to finish: close the release and push it.
```
-git flow release finish 3.15.3
+git flow release finish 3.15.4
git push --all
git push --tags
```
@@ -75,7 +75,7 @@ grunt
grunt publish
```
-For example, if we are in 3.15.3 and we want to go back to 3.13.4
+For example, if we are in 3.15.4 and we want to go back to 3.13.4
```
git checkout 3.13.4
diff --git a/doc/API.md b/doc/API.md
index cc0a496228..b8a02be3b1 100644
--- a/doc/API.md
+++ b/doc/API.md
@@ -1182,16 +1182,16 @@ cartodb.Image(vizjson_url)
An _Image_ object
-#### Image.getURL(_callback(err, url)_)
+#### Image.getUrl(_callback(err, url)_)
Gets the URL for the image requested.
-
Image.getURL
+
Image.getUrl
```javascript
@@ -1452,10 +1452,10 @@ Anytime you wish to push a stable version of your site to the web though, you ca
alert(cartodb.VERSION)
```
-Once you know which version of CartoDB.js you're using, you can point your site to that release. If the current version of CartoDB.js is 3.15.3, the URL would be:
+Once you know which version of CartoDB.js you're using, you can point your site to that release. If the current version of CartoDB.js is 3.15.4, the URL would be:
```html
-
+
```
You can do the same for the CSS documents we provide:
diff --git a/examples/header_overlay.html b/examples/header_overlay.html
new file mode 100644
index 0000000000..f965209ad6
--- /dev/null
+++ b/examples/header_overlay.html
@@ -0,0 +1,80 @@
+
+
+
+ Header with createLayer | CartoDB.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
index 47d0e458a8..ef1abc7e82 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "cartodb.js",
- "version": "3.15.3",
+ "version": "3.15.4",
"description": "CartoDB javascript library",
"repository": {
"type": "git",
diff --git a/src/cartodb.js b/src/cartodb.js
index 2293829efa..bb418ffcbf 100644
--- a/src/cartodb.js
+++ b/src/cartodb.js
@@ -5,7 +5,7 @@
var cdb = root.cdb = {};
- cdb.VERSION = "3.15.3";
+ cdb.VERSION = "3.15.4";
cdb.DEBUG = false;
cdb.CARTOCSS_VERSIONS = {
diff --git a/src/geo/gmaps/gmaps.js b/src/geo/gmaps/gmaps.js
index 11bb085462..77082feea6 100644
--- a/src/geo/gmaps/gmaps.js
+++ b/src/geo/gmaps/gmaps.js
@@ -83,6 +83,7 @@ if(typeof(google) != "undefined" && typeof(google.maps) != "undefined") {
this._bindModel();
this._addLayers();
+ this.setAttribution();
google.maps.event.addListener(this.map_googlemaps, 'center_changed', function() {
var c = self.map_googlemaps.getCenter();
@@ -116,7 +117,6 @@ if(typeof(google) != "undefined" && typeof(google.maps) != "undefined") {
this.projector = new cdb.geo.CartoDBLayerGroupGMaps.Projector(this.map_googlemaps);
this.projector.draw = this._ready;
-
},
_ready: function() {
@@ -208,21 +208,7 @@ if(typeof(google) != "undefined" && typeof(google.maps) != "undefined") {
cdb.log.error("layer type not supported");
}
- var attribution = layer.get('attribution');
-
- if (attribution && attribution !== '') {
- // Setting attribution in map model
- // it doesn't persist in the backend, so this is needed.
- var attributions = _.clone(this.map.get('attribution')) || [];
- if (!_.contains(attributions, attribution)) {
- attributions.unshift(attribution);
- }
-
- this.map.set({ attribution: attributions });
- }
-
return layer_view;
-
},
pixelToLatLon: function(pos) {
@@ -266,10 +252,10 @@ if(typeof(google) != "undefined" && typeof(google.maps) != "undefined") {
return [ [0,0], [0,0] ];
},
- setAttribution: function(m) {
+ setAttribution: function() {
// Remove old one
var old = document.getElementById("cartodb-gmaps-attribution")
- , attribution = m.get("attribution").join(", ");
+ , attribution = this.map.get("attribution").join(", ");
// If div already exists, remove it
if (old) {
diff --git a/src/geo/leaflet/leaflet.js b/src/geo/leaflet/leaflet.js
index 317efc4a07..fa557439d7 100644
--- a/src/geo/leaflet/leaflet.js
+++ b/src/geo/leaflet/leaflet.js
@@ -70,8 +70,8 @@
this.map.geometries.bind('remove', this._removeGeometry, this);
this._bindModel();
-
this._addLayers();
+ this.setAttribution();
this.map_leaflet.on('layeradd', function(lyr) {
this.trigger('layeradd', lyr, self);
@@ -254,19 +254,6 @@
lv.setZIndex(lv.model.get('order'));
}
- var attribution = layer.get('attribution');
-
- if (attribution && attribution !== '') {
- // Setting attribution in map model
- // it doesn't persist in the backend, so this is needed.
- var attributions = _.clone(this.map.get('attribution')) || [];
- if (!_.contains(attributions, attribution)) {
- attributions.unshift(attribution);
- }
-
- this.map.set({ attribution: attributions });
- }
-
if(opts === undefined || !opts.silent) {
this.trigger('newLayerView', layer_view, layer_view.model, this);
}
diff --git a/src/geo/map.js b/src/geo/map.js
index e1c9217871..b820563266 100644
--- a/src/geo/map.js
+++ b/src/geo/map.js
@@ -294,9 +294,28 @@ cdb.geo.Map = cdb.core.Model.extend({
}
}, this);
+ this.layers.bind('reset', this._updateAttributions, this);
+ this.layers.bind('add', this._updateAttributions, this);
+ this.layers.bind('remove', this._updateAttributions, this);
+ this.layers.bind('change:attribution', this._updateAttributions, this);
+
this.geometries = new cdb.geo.Geometries();
},
+ _updateAttributions: function() {
+ var defaultCartoDBAttribution = this.defaults.attribution[0];
+ var attributions = _.chain(this.layers.models)
+ .map(function(layer) { return layer.get('attribution'); })
+ .reject(function(attribution) { return attribution == defaultCartoDBAttribution})
+ .compact()
+ .uniq()
+ .value();
+
+ attributions.push(defaultCartoDBAttribution);
+
+ this.set('attribution', attributions);
+ },
+
setView: function(latlng, zoom) {
this.set({
center: latlng,
@@ -462,24 +481,6 @@ cdb.geo.Map = cdb.core.Model.extend({
}
},
- updateAttribution: function(old, new_) {
- var attributions = this.get("attribution") || [];
-
- // Remove the old one
- if (old) {
- attributions = _.without(attributions, old);
- }
-
- // Save the new one
- if (new_) {
- if (!_.contains(attributions, new_)) {
- attributions.push(new_);
- }
- }
-
- this.set({ attribution: attributions });
- },
-
addGeometry: function(geom) {
this.geometries.add(geom);
},
@@ -663,7 +664,7 @@ cdb.geo.MapView = cdb.core.View.extend({
this.map.bind('change:scrollwheel', this._setScrollWheel, this);
this.map.bind('change:keyboard', this._setKeyboard, this);
this.map.bind('change:center', this._setCenter, this);
- this.map.bind('change:attribution', this._setAttribution, this);
+ this.map.bind('change:attribution', this.setAttribution, this);
},
/** unbind model properties */
@@ -688,10 +689,6 @@ cdb.geo.MapView = cdb.core.View.extend({
this.map.fitBounds(bounds, this.getSize())
},
- _setAttribution: function(m,attr) {
- this.setAttribution(m);
- },
-
_addLayers: function() {
var self = this;
this._removeLayers();
diff --git a/src/geo/ui/fullscreen.js b/src/geo/ui/fullscreen.js
index 07cd874a04..0adb69682f 100644
--- a/src/geo/ui/fullscreen.js
+++ b/src/geo/ui/fullscreen.js
@@ -99,14 +99,42 @@ cdb.ui.common.FullScreen = cdb.core.View.extend({
},
render: function() {
+ if (this._canFullScreenBeEnabled()) {
+ var $el = this.$el;
+ var options = _.extend(this.options);
+ $el.html(this.options.template(options));
+ } else {
+ cdb.log.info('FullScreen is deprecated on insecure origins. See https://goo.gl/rStTGz for more details.');
+ }
- var $el = this.$el;
+ return this;
+ },
- var options = _.extend(this.options);
+ _canFullScreenBeEnabled: function() {
+ // If frameElement exists, it means that the map
+ // is embebed as an iframe so we need to check if
+ // the parent has a secure protocol
+ var frameElement = window && window.frameElement;
+ if (frameElement) {
+ var parentWindow = this._getFramedWindow(frameElement);
+ var parentProtocol = parentWindow.location.protocol;
+ if (parentProtocol.search('https:') !== 0) {
+ return false;
+ }
+ }
- $el.html(this.options.template(options));
+ return true;
+ },
- return this;
+ _getFramedWindow: function(f) {
+ if (f.parentNode == null) {
+ f = document.body.appendChild(f);
+ }
+ var w = (f.contentWindow || f.contentDocument);
+ if (w && w.nodeType && w.nodeType==9) {
+ w = (w.defaultView || w.parentWindow);
+ }
+ return w;
}
});
diff --git a/test/spec/geo/gmaps/gmaps.spec.js b/test/spec/geo/gmaps/gmaps.spec.js
index 991e5c76ce..c64275915f 100644
--- a/test/spec/geo/gmaps/gmaps.spec.js
+++ b/test/spec/geo/gmaps/gmaps.spec.js
@@ -234,20 +234,4 @@
done();
}, 2000);
});
-
- it("should set the attributions on the map when layers are added", function() {
- var layer1 = new cdb.geo.CartoDBLayer({ type: 'cartodb', attribution: 'attribution1', table_name: "table1", tile_style: 'test', user_name: 'test' });
- var layer2 = new cdb.geo.CartoDBLayer({ type: 'cartodb', attribution: 'attribution2', table_name: "table2", tile_style: 'test', user_name: 'test' });
- var layer3 = new cdb.geo.CartoDBLayer({ type: 'cartodb', attribution: '', table_name: "table2", tile_style: 'test', user_name: 'test' });
-
- map.layers.reset([layer1, layer2, layer3]);
-
- expect(map.get('attribution')).toEqual([
- 'attribution2',
- 'attribution1',
- 'CartoDB attribution'
- ]);
- });
-
});
-
diff --git a/test/spec/geo/leaflet/leaflet.spec.js b/test/spec/geo/leaflet/leaflet.spec.js
index af7687afd0..bf64753e8d 100644
--- a/test/spec/geo/leaflet/leaflet.spec.js
+++ b/test/spec/geo/leaflet/leaflet.spec.js
@@ -293,20 +293,6 @@ describe('LeafletMapView', function() {
expect(mapView.layers[newLayer.cid].check).toEqual('testing');
});
- it("should set the attributions on the map when layers are added", function() {
- var layer1 = new cdb.geo.CartoDBLayer({ type: 'cartodb', attribution: 'attribution1', table_name: "table1", tile_style: 'test', user_name: 'test' });
- var layer2 = new cdb.geo.CartoDBLayer({ type: 'cartodb', attribution: 'attribution2', table_name: "table2", tile_style: 'test', user_name: 'test' });
- var layer3 = new cdb.geo.CartoDBLayer({ type: 'cartodb', attribution: '', table_name: "table2", tile_style: 'test', user_name: 'test' });
-
- map.layers.reset([layer1, layer2, layer3]);
-
- expect(map.get('attribution')).toEqual([
- 'attribution2',
- 'attribution1',
- 'CartoDB attribution'
- ]);
- });
-
// Test cases for gmaps substitutes since the support is deprecated.
_({ // GMaps basemap base_type: expected substitute data
//empty = defaults to gray_roadmap
diff --git a/test/spec/geo/map.spec.js b/test/spec/geo/map.spec.js
index fefd2ecf1b..8af9c8b005 100644
--- a/test/spec/geo/map.spec.js
+++ b/test/spec/geo/map.spec.js
@@ -227,6 +227,72 @@ describe("geo.map", function() {
expect(map.get('maxZoom')).toEqual(40);
expect(map.get('minZoom')).toEqual(0);
});
+
+ it('should update the attributions of the map when layers are reset/added/removed', function() {
+
+ map = new cdb.geo.Map();
+
+ // Map has the default CartoDB attribution
+ expect(map.get('attribution')).toEqual([
+ "CartoDB attribution"
+ ]);
+
+ var layer1 = new cdb.geo.CartoDBLayer({ attribution: 'attribution1' });
+ var layer2 = new cdb.geo.CartoDBLayer({ attribution: 'attribution1' });
+ var layer3 = new cdb.geo.CartoDBLayer({ attribution: 'wadus' });
+ var layer4 = new cdb.geo.CartoDBLayer({ attribution: '' });
+
+ map.layers.reset([ layer1, layer2, layer3, layer4 ]);
+
+ // Attributions have been updated removing duplicated and empty attributions
+ expect(map.get('attribution')).toEqual([
+ "attribution1",
+ "wadus",
+ "CartoDB attribution",
+ ]);
+
+ var layer = new cdb.geo.CartoDBLayer({ attribution: 'attribution2' });
+
+ map.layers.add(layer);
+
+ // The attribution of the new layer has been appended before the default CartoDB attribution
+ expect(map.get('attribution')).toEqual([
+ "attribution1",
+ "wadus",
+ "attribution2",
+ "CartoDB attribution",
+ ]);
+
+ layer.set('attribution', 'new attribution');
+
+ // The attribution of the layer has been updated in the map
+ expect(map.get('attribution')).toEqual([
+ "attribution1",
+ "wadus",
+ "new attribution",
+ "CartoDB attribution",
+ ]);
+
+ map.layers.remove(layer);
+
+ expect(map.get('attribution')).toEqual([
+ "attribution1",
+ "wadus",
+ "CartoDB attribution",
+ ]);
+
+ // Addind a layer with the default attribution
+ var layer = new cdb.geo.CartoDBLayer();
+
+ map.layers.add(layer, { at: 0 });
+
+ // Default CartoDB only appears once and it's the last one
+ expect(map.get('attribution')).toEqual([
+ "attribution1",
+ "wadus",
+ "CartoDB attribution",
+ ]);
+ })
});
describe('MapView', function() {
diff --git a/test/spec/geo/ui/mobile.spec.js b/test/spec/geo/ui/mobile.spec.js
index 7cf135ebe1..f63c8356d9 100644
--- a/test/spec/geo/ui/mobile.spec.js
+++ b/test/spec/geo/ui/mobile.spec.js
@@ -61,7 +61,7 @@ describe("cdb.geo.ui.Mobile", function() {
}
});
- map.layers = new cdb.geo.Layers([l1, layerGroup]);
+ map.layers.reset([l1, layerGroup]);
template = cdb.core.Template.compile('\\