cdb.admin.overlays.MobileLayers = cdb.core.View.extend({
className: "layer-container",
template: cdb.core.Template.compile('
'),
initialize: function() {
this.layers = [];
this.layerViews = [];
this.model = new Backbone.Model({
layer_count: 0,
show_title: this.options.show_title,
force_hidden_title: this.options.force_hidden_title,
show_layer_selector: this.options.show_layer_selector,
show_legends: this.options.show_legends || false
});
this.model.on("change:layer_count", this._onChangeLayerCount, this);
this.model.on("change:show_title", this._onChangeShowTitle, this);
this.model.on("change:show_legends", this._onChangeShowLegends, this);
this.model.on("change:show_layer_selector", this._onChangeShowLayerSelector, this);
this.map = this.options.map;
this.mapView = this.options.mapView;
this.map.layers.on("change", function() {
this._reloadLayers();
}, this);
_.each(this.map.layers.models, this._getLayer, this);
},
getLayerCount: function() {
return this.layerViews.length;
},
_onChangeShowLayerSelector: function() {
this._reloadLayers();
},
_onChangeShowLegends: function() {
this._reloadLayers();
},
_onChangeLayerCount: function() {
var layerCount = this.model.get("layer_count");
if (layerCount === 0) {
this.trigger("hide-layers", this);
if (!this.model.get("force_hidden_title")) this.model.set("show_title", false);
} else {
this.trigger("show-layers", this);
var msg = layerCount + " layer" + (layerCount != 1 ? "s" : "");
this.$el.find(" > h3").text(msg)
if (!this.model.get("force_hidden_title")) this.model.set("show_title", true);
}
},
_onChangeShowTitle: function() {
if (this.model.get("show_title")) this._showTitle();
else this._hideTitle();
},
_addTitle: function() {
var layerCount = this.model.get("layer_count");
var msg = layerCount + " layer" + (layerCount != 1 ? "s" : "");
this.$el.prepend("" + msg + "
");
if (!this.model.get("show_title")) this.$el.find("> h3").hide();
},
showTitle: function(force) {
if (force) this.model.set("force_hidden_title", false);
this.model.set("show_title", true);
},
hideTitle: function(force) {
if (force) this.model.set("force_hidden_title", true);
this.model.set("show_title", false);
},
_showTitle: function() {
this.$el.find("> h3").show();
},
_hideTitle: function() {
this.$el.find("> h3").hide();
},
showLayerSelector: function() {
this.model.set("show_layer_selector", true);
},
hideLayerSelector: function() {
this.model.set("show_layer_selector", false);
},
toggleLegends: function() {
this.model.set("show_legends", !this.model.get("show_legends"));
},
_getLayer: function(layer) {
if (layer.get("type") === "CartoDB" || layer.get('type') === 'torque') {
this.layers.push(layer);
}
},
_renderLayer: function(data) {
var hasLegend = data.legend && data.legend.get("type") !== "" && data.legend.get("type") !== "none";
var showLayerSelector = this.model.get("show_layer_selector");
var showLegends = this.model.get("show_legends");
var layer = new cdb.admin.overlays.MobileLayer({
model: data,
show_legends: showLegends,
show_title: showLayerSelector,
hide_toggle: !showLayerSelector
});
if (layer.model.get("type") === "torque" && layer.model.get("visible")) {
var torqueLayer = this._getTorqueLayer();
this.trigger("add-torque", torqueLayer);
}
// Let's see if we should render the layer
if (!showLayerSelector && !showLegends) return;
if (!showLayerSelector && !hasLegend) return;
if (!showLayerSelector && !data.get("visible")) return;
if (data.wizard_properties) {
data.wizard_properties.off("change", this._onChangeWizardProperties, this);
data.wizard_properties.on("change", this._onChangeWizardProperties, this);
}
this.layerViews.push(layer);
this.addView(layer);
this.$el.find(".layers").append(layer.render().$el);
layer.bind("change_visibility", this._reInitScrollpane, this);
},
_onChangeWizardProperties: function(model) {
this._reloadLayers();
},
_getTorqueLayer: function() {
var layer = this.map.layers.getLayersByType('torque')[0];
if (layer) {
return this.mapView.getLayerByCid(layer.cid);
}
},
_reloadLayers: function() {
this.layers = [];
_.each(this.map.layers.models, this._getLayer, this);
this._removeTorque();
this._removeLayers();
this._renderLayers();
},
_removeTorque: function() {
this.trigger("remove-torque", this);
},
_removeLayers: function() {
_.each(this.layerViews, function(layer) {
layer.clean();
}, this);
this.layerViews = [];
},
_renderLayers: function() {
_.each(this.layers, this._renderLayer, this);
this.model.set("layer_count", this.layerViews.length);
this._reInitScrollpane();
},
_reInitScrollpane: function() {
this.$('.scrollpane').data('jsp') && this.$('.scrollpane').data('jsp').reinitialise();
},
render: function() {
this.$el.append(this.template);
this._renderLayers();
this._addTitle();
return this;
}
});
cdb.admin.overlays.MobileHeader = cdb.core.View.extend({
className: "hgroup",
template: _.template('<% if (show_title) { %><%- title %>
<% } %><% if (show_description) { %><%- description %><% } %>
'),
initialize: function() {
var extra = this.model.get("extra");
this.model.on("change:title", this._onChangeTitle, this);
this.model.on("change:description", this._onChangeDescription, this);
this.model.on("change:show_title", this._onChangeShowTitle, this);
this.model.on("change:show_description", this._onChangeShowDescription, this);
},
_onChangeShowTitle: function() {
this.render();
},
_onChangeShowDescription: function() {
this.render();
},
_onChangeTitle: function() {
this.render();
},
_onChangeDescription: function() {
this.render();
},
render: function() {
var extra = this.model.get("extra");
var showTitle = false;
var showDescription = false;
if (extra.title && extra.show_title) {
showTitle = true;
}
if (extra.description && extra.show_description) {
showDescription = true;
}
this.$el.html(this.template({
title: extra.title,
show_title:showTitle,
description: extra.description,
show_description: showDescription
}));
return this;
}
});
cdb.admin.overlays.MobileLayer = cdb.core.View.extend({
tagName: "li",
events: {
'click h3': "_toggle",
"dblclick": "_stopPropagation"
},
className: "cartodb-mobile-layer",
template: cdb.core.Template.compile("<% if (show_title) { %><%- layer_name %><% } %>
"),
/**
* Stop event propagation
*/
_stopPropagation: function(ev) {
ev.stopPropagation();
},
initialize: function() {
_.defaults(this.options, this.default_options);
this.model.on("change:table_name_alias", this._onChangeLayerName, this);
this.model.on("change:visible", this._onChangeVisible, this);
if (this.model.legend) {
this.model.legend.off("add change remove", this._reloadLegend, this);
this.model.legend.on("add change remove", this._reloadLegend, this);
}
},
_onChangeLayerName: function() {
this.$el.find("h3 span", this._getLayerName());
},
_onChangeVisible: function() {
this.$el.find(".legend")[ this.model.get("visible") ? "fadeIn":"fadeOut"](150);
this.$el[ this.model.get("visible") ? "removeClass":"addClass"]("hidden");
this.trigger("change_visibility", this);
},
_toggle: function(e) {
e.preventDefault();
e.stopPropagation();
if (this.options.hide_toggle) return;
this.model.set("visible", !this.model.get("visible"))
},
_reloadLegend: function() {
this.$el.removeClass("has-legend");
if (this.legend) {
this.legend.clean();
delete this.legend;
}
this._renderLegend();
},
_renderLegend: function() {
if (!this.options.show_legends) return;
if (this.model.legend && (this.model.legend.get("type") === "none" || !this.model.legend.get("type"))) return;
if (this.model.legend && this.model.legend.get("items") && this.model.legend.get("items").length === 0) return;
this.$el.addClass("has-legend");
this.legend = new cdb.geo.ui.Legend({ model: this.model.legend });
this.addView(this.legend);
this.legend.undelegateEvents();
this.$el.append(this.legend.render().$el);
},
_truncate: function(input, length) {
return input.substr(0, length-1) + (input.length > length ? '…' : '');
},
_getLayerName: function() {
return this.model.get("table_name_alias") || this.model.get("table_name");
},
render: function() {
var attributes = _.extend(this.model.attributes, {
show_title: this.options.show_title,
layer_name: this._getLayerName(),
toggle_class: this.options.hide_toggle ? " hide" : ""
});
this.$el.html(this.template(attributes));
if (!this.model.get("visible")) this.$el.addClass("hidden");
if (this.model.get("legend")) this._renderLegend();
this._onChangeVisible();
return this;
}
});
cdb.admin.overlays.Mobile = cdb.core.View.extend({
className: "cartodb-mobile",
template_name: "table/views/mobile",
events: {
"click .cartodb-attribution-button": "_onAttributionClick",
"click .toggle": "_toggle",
"click .fullscreen": "_toggleFullScreen",
"click .backdrop": "_onBackdropClick",
"dblclick .aside": "_stopPropagation",
"dragstart .aside": "_checkOrigin",
"mousedown .aside": "_checkOrigin",
"touchstart .aside": "_checkOrigin",
"MSPointerDown .aside": "_checkOrigin",
},
initialize: function() {
_.bindAll(this, "_toggle", "_reInitScrollpane");
_.defaults(this.options, this.default_options);
this.visibility_options = this.options.visibility_options || {};
this.mapView = this.options.mapView;
this.map = this.mapView.map;
this.map.on("change:legends", this._toggleLegends, this);
this.template = this.options.template ? this.options.template : this.getTemplate(this.template_name);
this._bindOverlays();
this.model = new Backbone.Model({
open: false,
show_layer_selector: false
});
this.model.on("change:open", this._onChangeOpen, this);
},
show: function() {
this.$el.fadeIn(250);
},
hide: function() {
this.$el.fadeOut(250);
},
/**
* Check event origin
*/
_checkOrigin: function(ev) {
// If the mouse down come from jspVerticalBar
// dont stop the propagation, but if the event
// is a touchstart, stop the propagation
var come_from_scroll = (($(ev.target).closest(".jspVerticalBar").length > 0) && (ev.type != "touchstart"));
if (!come_from_scroll) {
ev.stopPropagation();
}
},
_stopPropagation: function(ev) {
ev.stopPropagation();
},
_onBackdropClick: function(e) {
e.preventDefault();
e.stopPropagation();
this.$el.find(".backdrop").fadeOut(250);
this.$el.find(".cartodb-attribution").fadeOut(250);
},
_onAttributionClick: function(e) {
e.preventDefault();
e.stopPropagation();
this.$el.find(".backdrop").fadeIn(250);
this.$el.find(".cartodb-attribution").fadeIn(250);
},
_toggle: function(e) {
e.preventDefault();
e.stopPropagation();
this.model.set("open", !this.model.get("open"));
},
_toggleLegends: function(){
this.layers.toggleLegends();
},
_toggleFullScreen: function(ev) {
ev.stopPropagation();
ev.preventDefault();
var doc = window.document;
var docEl = doc.documentElement;
if (this.options.doc) { // we use a custom element
docEl = $(this.options.doc)[0];
}
var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen;
var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen;
var mapView = this.options.mapView;
if (!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement) {
requestFullScreen.call(docEl);
if (mapView) {
if (this.model.get("allowWheelOnFullscreen")) {
mapView.options.map.set("scrollwheel", true);
}
}
} else {
cancelFullScreen.call(doc);
}
},
_open: function() {
var right = this.$el.find(".aside").width();
this.$el.find(".cartodb-header").animate({ right: right }, 200)
this.$el.find(".aside").animate({ right: 0 }, 200)
this.$el.find(".cartodb-attribution-button").animate({ right: right + parseInt(this.$el.find(".cartodb-attribution-button").css("right")) }, 200)
this.$el.find(".cartodb-attribution").animate({ right: right + parseInt(this.$el.find(".cartodb-attribution-button").css("right")) }, 200)
this._initScrollPane();
},
_close: function() {
this.$el.find(".cartodb-header").animate({ right: 0 }, 200)
this.$el.find(".aside").animate({ right: - this.$el.find(".aside").width() }, 200)
this.$el.find(".cartodb-attribution-button").animate({ right: 20 }, 200)
this.$el.find(".cartodb-attribution").animate({ right: 20 }, 200)
},
default_options: {
timeout: 0,
msg: ''
},
_stopPropagation: function(ev) {
ev.stopPropagation();
},
_bindOverlays: function() {
this.overlays = this.options.overlays;
this.overlays.on("add", function() {
this._resetOverlays();
}, this);
this.overlays.on("remove", function() {
this._resetOverlays();
}, this);
},
_onChangeOpen: function() {
this.model.get("open") ? this._open() : this._close();
},
_createLayer: function(_class, opts) {
return new cdb.geo.ui[_class](opts);
},
_reInitScrollpane: function() {
this.$('.scrollpane').data('jsp') && this.$('.scrollpane').data('jsp').reinitialise();
},
_removeOverlays: function() {
this._removeLayerSelector();
this._removeHeader();
this._removeSearch();
this._removeFullscreen();
},
_resetOverlays: function() {
this._removeOverlays();
this._renderOverlays();
if (!this.model.get("show_layer_selector") && !this.model.get("show_search") && !this.map.get("legends")) this.model.set("open", false);
if (this.layers.layers.length === 0 && !this.model.get("search")) this.model.set("open", false);
},
_renderOverlays: function() {
_.each(this.overlays.models, function(overlay) {
var overlayType = overlay.get("type");
if (overlayType === 'search') {
this._addSearch(overlay);
}
if (overlayType === 'layer_selector') {
this._addLayerSelector();
}
if (overlayType === 'fullscreen') {
this._addFullscreen(overlay);
}
if (overlayType === 'header') {
this._addHeader(overlay);
}
}, this);
},
render:function() {
this.$el.html(this.template(this.options));
this._renderOverlays();
this._addAttributions();
this._addLayers();
return this;
},
_initScrollPane: function() {
if (this.$scrollpane) return;
var self = this;
var height = this.$el.height();
this.$scrollpane = this.$el.find(".scrollpane");
setTimeout(function() {
self.$scrollpane.css("max-height", height - 60);
self.$scrollpane.jScrollPane({ showArrows: true });
}, 500);
},
_removeLayerSelector: function() {
this.model.set("show_layer_selector", false);
if (this.layers) this.layers.hideLayerSelector();
},
_addLayerSelector: function(overlay) {
this.model.set("show_layer_selector", true);
if (this.layers) this.layers.showLayerSelector();
},
_addFullscreen: function(overlay) {
this.$el.addClass("with-fullscreen");
},
_addSearch: function(overlay) {
this.model.set("show_search", true);
this.search = new cdb.geo.ui.Search({
template: this.getTemplate("table/views/search_control"),
model: this.options.map,
mapView: this.options.mapView
});
this.addView(this.search);
this.$el.addClass("with-search");
this.$el.find(".aside").prepend(this.search.render().$el);
this.search.$el.find("input[type='text']").attr("placeholder", "Search for places…");
if (this.layers) this.layers.hideTitle(true);
},
_addHeader: function(overlay) {
this.header = new cdb.admin.overlays.MobileHeader({ model: overlay });
this.addView(this.header);
this.$el.addClass("with-header");
this.$el.find(".cartodb-header .content").append(this.header.render().$el);
},
_removeFullscreen: function() {
this.$el.removeClass("with-fullscreen");
},
_removeSearch: function() {
this.model.set("show_search", false);
this.$el.removeClass("with-search");
if (this.search) {
this.search.clean();
delete this.search;
}
if (this.layers) this.layers.showTitle();
},
_removeHeader: function() {
this.$el.removeClass("with-header");
if (this.header) {
this.header.clean();
delete this.header;
}
},
_addAttributions: function() {
var attributions = "";
this.options.mapView.$el.find(".leaflet-control-attribution").hide(); // TODO: remove this from here
if (this.options.layerView) {
attributions = this.options.layerView.model.get("attribution");
this.$el.find(".cartodb-attribution").append(attributions);
} else if (this.options.map.get("attribution")) {
attributions = this.options.map.get("attribution");
_.each(attributions, function(attribution) {
var $li = $("");
var $el = $li.html(attribution);
this.$el.find(".cartodb-attribution").append($li);
}, this);
}
if (attributions) {
this.$el.find(".cartodb-attribution-button").fadeIn(250);
}
},
_removeLayers: function() {
this.$el.removeClass("with-layers");
if (this.layers) {
this.layers.clean();
delete this.layers;
}
},
_addLayers: function() {
this.layers = new cdb.admin.overlays.MobileLayers({
map: this.map,
mapView: this.mapView,
show_legends: this.map.get("legends"),
show_title: !this.model.get("show_search"),
force_hidden_title: this.model.get("show_search"),
show_layer_selector: this.model.get("show_layer_selector")
});
this.layers.bind("remove-torque", function(torqueLayer) {
this._removeTorque();
}, this);
this.layers.bind("add-torque", function(torqueLayer) {
this._addTorqueLayer(torqueLayer);
}, this);
this.layers.bind("show-layers", function() {
this.$el.addClass("with-layers");
}, this);
this.layers.bind("hide-layers", function() {
this.$el.removeClass("with-layers");
}, this);
this.addView(this.layers);
this.$el.find(".aside").append(this.layers.render().$el);
},
_removeTorque: function() {
this.$el.removeClass("with-torque");
if (this.slider) {
this.slider.clean();
this.slider = null;
}
},
_addTorqueLayer: function(layer) {
this.slider = new cdb.geo.ui.TimeSlider({type: "time_slider", layer: layer, map: this.options.map, pos_margin: 0, position: "none" , width: "auto" });
this.addView(this.slider);
this.slider.bind("time_clicked", function() {
this.slider.toggleTime();
}, this);
this.$el.find(".torque").append(this.slider.render().$el);
this.$el.addClass("with-torque");
}
});