312 lines
9.0 KiB
JavaScript
312 lines
9.0 KiB
JavaScript
/**
|
||
* this infowindow is shown in the map when user clicks on a feature
|
||
*/
|
||
|
||
(function() {
|
||
|
||
var MapInfowindow = cdb.geo.ui.Infowindow.extend({
|
||
|
||
_TEXTS: {
|
||
_NO_FIELDS_SELECTED: _t("You haven’t selected any fields to be shown in the infowindow."),
|
||
_NO_FIELDS_SELECTED_BUTTON: _t("Select fields")
|
||
},
|
||
|
||
_TEMPLATE_URL: 'table/views/infowindow/templates',
|
||
|
||
events: cdb.core.View.extendEvents({
|
||
'click .edit_data': '_editData',
|
||
'click .edit_geo': '_editGeom',
|
||
'click .remove': '_removeGeom',
|
||
'click .open_infowindow_panel': '_openInfowindowPanel'
|
||
}),
|
||
|
||
initialize: function() {
|
||
var self = this;
|
||
_.bindAll(this, '_removeGeom');
|
||
this.table = this.options.table;
|
||
this.model.set({ content: 'loading...' });
|
||
// call parent
|
||
this.constructor.__super__.initialize.apply(this);
|
||
this.model.set('offset', [28, 0]);
|
||
this.model.bind('change:fields', function() {
|
||
if (!this.hasChanged('content') && self.row) {
|
||
self.renderInfo();
|
||
}
|
||
});
|
||
|
||
this.table.bind('change:schema', this.render, this);
|
||
this.add_related_model(this.table);
|
||
|
||
// Create a help dialog for the infowindows with images
|
||
if (this._containsCover) this._createHelpDialog();
|
||
|
||
// Set live tipsy when geom is enabled or disabled
|
||
this.$("div.cartodb-edit-buttons a.button").tipsy({
|
||
live:true,
|
||
fade:true,
|
||
gravity: 's',
|
||
offset: -2,
|
||
className: function(){
|
||
return $(this).closest(".cartodb-popup").hasClass('dark') ? 'dark' : ''
|
||
},
|
||
title: function(ev){
|
||
var enabled = !$(this).hasClass("disabled");
|
||
if (enabled) {
|
||
return $(this).text()
|
||
} else {
|
||
return 'Not available in this mode'
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
_createHelpDialog: function() {
|
||
this.helpDialog = cdb.editor.ViewFactory.createDialogByTemplate('common/dialogs/help/infowindow_with_images', {}, { clean_on_hide: false });
|
||
this.addView(this.helpDialog);
|
||
},
|
||
|
||
setFeatureInfo: function(cartodb_id) {
|
||
// Set cartodb_id
|
||
this.cartodb_id = cartodb_id;
|
||
|
||
// render to update cartodb_id
|
||
this.render();
|
||
|
||
// Get row data and show the content
|
||
if(this.row) {
|
||
this.row.unbind(null, null, this);
|
||
}
|
||
this.row = this.table.data().getRow(cartodb_id, {
|
||
no_add: true
|
||
});
|
||
|
||
this.row
|
||
.bind('change', this.renderInfo, this)
|
||
.fetch({ cache: false, no_geom: true });
|
||
|
||
// trigger renderInfo now to render the actual contents
|
||
this.renderInfo();
|
||
|
||
return this;
|
||
},
|
||
|
||
/**
|
||
* renders the infowindows adding some editing features
|
||
*/
|
||
render: function() {
|
||
|
||
var self = this;
|
||
|
||
// render original
|
||
cdb.geo.ui.Infowindow.prototype.render.call(this);
|
||
|
||
var fields = this.model.get('fields');
|
||
|
||
// Show no_fields state when there isn't any field
|
||
// and a custom template is not selected
|
||
if((!fields || (fields && !fields.length)) && (!this.model.get('template'))) {
|
||
|
||
// Add empty fields to the infowindow
|
||
this.$('.cartodb-popup').addClass("no_fields");
|
||
|
||
// Check if the infowindow has header or not
|
||
var popup_class = '.cartodb-popup-content';
|
||
if (this.$('.cartodb-popup-header').length > 0) {
|
||
popup_class = '.cartodb-popup-header';
|
||
}
|
||
|
||
this.$(popup_class).html(
|
||
'<p class="italic">' + this._TEXTS._NO_FIELDS_SELECTED + '</p>' +
|
||
'<p><a class="margin5 underline open_infowindow_panel" href="#/select-fields">' + this._TEXTS._NO_FIELDS_SELECTED_BUTTON + '</a></p>'
|
||
)
|
||
} else {
|
||
this.$('.cartodb-popup').removeClass("no_fields");
|
||
}
|
||
|
||
|
||
// render edit and remove buttons
|
||
this.$('.cartodb-popup-content-wrapper')
|
||
.append(this.getTemplate('table/views/infowindow/infowindow_footer')({ "cartodb_id": this.cartodb_id }));
|
||
|
||
if (this.table.isReadOnly()) {
|
||
this.$('.cartodb-popup-content-wrapper').find('a.remove, a.edit_data, a.edit_geo').addClass('disabled');
|
||
}
|
||
|
||
if (this._containsCover()) { // bind the help link to the helpDialog
|
||
this.$(".image_not_found a.help").off("click");
|
||
this.$(".image_not_found a.help").on("click", function() {
|
||
$('body').append(self.helpDialog.render().el);
|
||
self.helpDialog.open();
|
||
});
|
||
}
|
||
|
||
},
|
||
|
||
renderInfo: function() {
|
||
var self = this;
|
||
var row_attributes = self.row.attributes;
|
||
var fields = [];
|
||
|
||
for (var property in row_attributes) {
|
||
if (row_attributes.hasOwnProperty(property)) {
|
||
if (self.model.containsField(property) && !_.contains(self.model.SYSTEM_COLUMNS, property)) {
|
||
var h = {
|
||
title: self.model.getFieldProperty(property, 'title') ? property : null,
|
||
value: row_attributes[property],
|
||
position: self.model.getFieldPos(property)
|
||
};
|
||
|
||
fields.push(h);
|
||
}
|
||
}
|
||
}
|
||
|
||
// sort
|
||
fields = _.compact(fields);
|
||
fields.sort(function(a, b) {
|
||
return a.position - b.position;
|
||
});
|
||
|
||
// filter and add index
|
||
var render_fields = [];
|
||
for(var i = 0; i < fields.length; ++i) {
|
||
var f = fields[i];
|
||
if(f) {
|
||
//
|
||
// header template use index to detect if it's the first element
|
||
// renderer to use special style.
|
||
// Mustache only matches as false a null, undefined or false value
|
||
// so for the first element we set index as null
|
||
// yes, very hacky :(
|
||
f.index = render_fields.length ? render_fields.length: null,
|
||
render_fields.push(f);
|
||
}
|
||
}
|
||
|
||
if (fields.length > 0) {
|
||
// Set content
|
||
this.model.set({ content: { fields: render_fields } });
|
||
} else {
|
||
// Show loading due to the fact that we don't have the content yet
|
||
this.setLoading();
|
||
}
|
||
|
||
if(this.model.get('visibility')) {
|
||
// Just move the map if need it when fields are already added.
|
||
this.adjustPan();
|
||
}
|
||
},
|
||
|
||
|
||
/**
|
||
* Attempts to load the cover URL and show it
|
||
*/
|
||
_loadCover: function() {
|
||
var self = this;
|
||
|
||
if (!this._containsCover()) return;
|
||
|
||
var $cover = this.$(".cover");
|
||
var $imageNotFound = this.$(".image_not_found");
|
||
var $img = $cover.find("img");
|
||
var url = this._getCoverURL();
|
||
|
||
if (!this._isValidURL(url)) {
|
||
$imageNotFound.fadeIn(250);
|
||
$img.hide();
|
||
return;
|
||
}
|
||
|
||
// configure spinner
|
||
var
|
||
target = document.getElementById('spinner'),
|
||
opts = { lines: 9, length: 4, width: 2, radius: 4, corners: 1, rotate: 0, color: '#ccc', speed: 1, trail: 60, shadow: true, hwaccel: false, zIndex: 2e9 },
|
||
spinner = new Spinner(opts).spin(target);
|
||
|
||
// create the image
|
||
$imageNotFound.hide();
|
||
|
||
$img.hide(function() {
|
||
this.remove();
|
||
});
|
||
|
||
$img = $("<img />").attr("src", url);
|
||
$cover.append($img);
|
||
|
||
$img.load(function(){
|
||
spinner.stop();
|
||
|
||
var w = $img.width();
|
||
var h = $img.height();
|
||
var coverWidth = $cover.width();
|
||
var coverHeight = $cover.height();
|
||
|
||
var ratio = h / w;
|
||
var coverRatio = coverHeight / coverWidth;
|
||
|
||
// Resize rules
|
||
if ( w > coverWidth && h > coverHeight) { // bigger image
|
||
if ( ratio < coverRatio ) $img.css({ height: coverHeight });
|
||
else {
|
||
var calculatedHeight = h / (w / coverWidth);
|
||
$img.css({ width: coverWidth, top: "50%", position: "absolute", "margin-top": -1*parseInt(calculatedHeight, 10)/2 });
|
||
}
|
||
} else {
|
||
var calculatedHeight = h / (w / coverWidth);
|
||
$img.css({ width: coverWidth, top: "50%", position: "absolute", "margin-top": -1*parseInt(calculatedHeight, 10)/2 });
|
||
}
|
||
|
||
$img.fadeIn(300);
|
||
})
|
||
.error(function(){
|
||
spinner.stop();
|
||
$imageNotFound.fadeIn(250);
|
||
});
|
||
},
|
||
|
||
|
||
/**
|
||
* triggers an editGeom event with the geometry
|
||
* infowindow is currently showing
|
||
*/
|
||
_editGeom: function(e) {
|
||
this.killEvent(e);
|
||
if (!this.table.isReadOnly()) {
|
||
this.model.set("visibility", false);
|
||
this.trigger('editGeom', this.row);
|
||
}
|
||
},
|
||
|
||
_editData: function(e) {
|
||
this.killEvent(e);
|
||
if (!this.table.isReadOnly()) {
|
||
this.model.set("visibility", false);
|
||
this.trigger('editData', this.row);
|
||
}
|
||
},
|
||
|
||
_removeGeom: function(e) {
|
||
this.killEvent(e);
|
||
if (!this.table.isReadOnly()) {
|
||
this.model.set("visibility", false);
|
||
this.trigger('removeGeom', this.row);
|
||
}
|
||
},
|
||
|
||
_openInfowindowPanel: function(e) {
|
||
this.killEvent(e);
|
||
this.trigger('openInfowindowPanel');
|
||
},
|
||
|
||
_getModelTemplate: function() {
|
||
var template_name = cdb.admin.mod.TemplateMap[this.model.get("template_name")] || this.model.get("template_name");
|
||
return this._TEMPLATE_URL + "/" + template_name;
|
||
}
|
||
|
||
});
|
||
|
||
// export
|
||
cdb.admin.MapInfowindow = MapInfowindow;
|
||
|
||
})();
|