cartodb-4.42/lib/assets/javascripts/cartodb/table/infowindow.js

312 lines
9.0 KiB
JavaScript
Raw Normal View History

2024-04-06 13:25:13 +08:00
/**
* 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;
})();