cartodb-4.42/lib/assets/javascripts/cartodb/table/infowindow.js
2024-04-06 05:25:13 +00:00

312 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 havent 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;
})();