/** * 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( '
' + this._TEXTS._NO_FIELDS_SELECTED + '
' + '' ) } 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 = $("").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; })();