cartodb-4.42/lib/assets/javascripts/dashboard/views/public-dataset/table-public-view.js

295 lines
8.6 KiB
JavaScript
Raw Normal View History

2024-04-06 13:25:13 +08:00
const $ = require('jquery');
const CoreView = require('backbone/core-view');
const UserModel = require('dashboard/data/user-model');
const AuthenticatedUserModel = require('dashboard/data/authenticated-user-model');
const SQLViewData = require('dashboard/data/table/sqlviewdata-model');
const PublicCartoTableMetadata = require('./public-carto-table-metadata');
const PublicHeader = require('./public-header/public-header');
const PublicTableTab = require('dashboard/views/public-dataset/table-tab/public-table-tab');
const TabPane = require('dashboard/components/tabpane/tabpane');
const MapView = require('dashboard/views/public-dataset/map-view/map-view');
const Tabs = require('dashboard/components/tabs/tabs');
const checkAndBuildOpts = require('builder/helpers/required-opts');
const ModalsServiceModel = require('builder/components/modals/modals-service-model');
const ViewFactory = require('builder/components/view-factory');
const templateApiDialog = require('dashboard/views/public-dataset/dialogs/api-call.tpl');
const PublicExportView = require('dashboard/views/public-dataset/dialogs/export/public-export-view');
const REQUIRED_OPTS = [
'configModel'
];
/**
* Table public view
*
*/
module.exports = CoreView.extend({
events: {
'click .js-Navmenu-link--download': '_exportTable',
'click .js-Navmenu-link--api': '_apiCallTable'
},
initialize: function (options) {
checkAndBuildOpts(options, REQUIRED_OPTS, this);
this._initModels();
this._initViews();
this._initBinds();
},
_initModels: function () {
this._modals = new ModalsServiceModel();
// Table
this.table = new PublicCartoTableMetadata({
id: this.options.table_name,
name: this.options.table_name,
description: this.options.vizjson.description || ''
}, { configModel: this._configModel });
this.table.set({
user_name: this.options.user_name,
vizjson: this.options.vizjson,
schema: this.options.schema
});
this.columns = this.table.data();
this.sqlView = new SQLViewData(null, {
configModel: this._configModel
});
this.sqlView.syncMethod = 'read';
var query = this.query = this.table.data().getSQL();
this.table.useSQLView(this.sqlView);
this.sqlView.options.set('rows_per_page', 20, { silent: true });
this._fetchData(query);
// User
this.user = new UserModel({ username: this.options.user_name });
// Authenticated user
this.authenticated_user = new AuthenticatedUserModel();
},
_initViews: function () {
// Public header
if (this.$('.cartodb-public-header').length > 0) {
var header = new PublicHeader({
el: this.$('.cartodb-public-header'),
model: this.authenticated_user,
vis: this.table,
current_view: this._getCurrentView(),
owner_username: this.options.owner_username,
isMobileDevice: this.options.isMobileDevice,
isCartoDBHosted: this._configModel.get('cartodb_com_hosted')
});
this.addView(header);
// Fetch authenticated user model
this.authenticated_user.fetch();
}
// Navigation - This is what switches the view on mobile
// TODO: this is insanely complex for just two buttons
// this.header = new cdb.open.PublicHeader({
// el: this.$('.navigation'),
// model: this.table,
// user: this.user,
// belong_organization: belong_organization,
// config: this.options.config
// });
// this.addView(this.header);
// Tabpanes
this.workViewTable = new TabPane({
el: this.$('.pane_table')
});
this.addView(this.workViewTable);
this.workViewMap = new TabPane({
el: this.$('.pane_map')
});
this.addView(this.workViewMap);
// Public app tabs
this.tabs = new Tabs({
el: this.$('.navigation ul'),
slash: true
});
this.addView(this.tabs);
// Help tooltip - I can't find any span with help class, I think this is unnecessary
// var tooltip = new cdb.common.TipsyTooltip({
// el: this.$('span.help'),
// gravity: $.fn.tipsy.autoBounds(250, 's')
// });
// this.addView(tooltip);
// Table tab
this.tableTab = new PublicTableTab({
configModel: this._configModel,
model: this.table,
vizjson: this.options.vizjson,
user_name: this.options.user_name
});
// Map tab
this.mapTab = new MapView({
username: this.options.user_name,
serverUrl: this._configModel.get('maps_api_template').replace('{user}', this.options.user_name),
sqlUrl: this._configModel.getSqlApiUrl(),
dataset: this.table.get('name'),
vizjson: this.table.get('vizjson'),
geometry: this.table.get('geometry_types')
});
this.listenTo(this.mapTab, 'mapBoundsChanged', function (options) {
const {
bounds,
center,
zoom
} = options;
this.model.set('map', {
bounds: [
bounds.getNorthEast().lng,
bounds.getNorthEast().lat,
bounds.getSouthWest().lng,
bounds.getSouthWest().lat
],
center,
zoom
});
});
this.listenTo(this.mapTab, 'boundsChanged', function (options) {
this.model.set('bounds', options.bounds);
});
this.workViewTable.addTab('table', this.tableTab.render());
this.workViewMap.addTab('map', this.mapTab.render());
this.workViewTable.active('table');
this.workViewMap.active('map');
this.mapTab.enableMap();
$('.pane_table').addClass('is-active');
},
_updateTable: function () {
var sql = (this.model.get('bounds') && this.model.get('map')) ? (this.query + ' WHERE the_geom && ST_MakeEnvelope(' + this.model.get('map')['bounds'][0] + ', ' + this.model.get('map')['bounds'][1] + ', ' + this.model.get('map')['bounds'][2] + ', ' + this.model.get('map')['bounds'][3] + ', 4326)') : this.query;
this._fetchData(sql);
},
_fetchData: function (sql) {
if (sql) {
this.sqlView.setSQL(sql);
}
this.sqlView.fetch({
success: () => {
this.$('.js-spinner').remove();
this.tableTab.deactivated();
this.tableTab.activated();
}
});
},
_exportTable: function (e) {
e.preventDefault();
// If a sql is applied but it is not valid, don't let the user export it
if (!this.sqlView.getSQL()) return false;
this._modals.create((modalModel) =>
new PublicExportView({
modalModel,
configModel: this._configModel,
model: this.table,
user_data: this.user.toJSON(),
bounds: this.sqlView.getSQL() !== this.query
})
);
},
_apiCallTable: function (e) {
e.preventDefault();
// If a sql is applied but it is not valid, don't show the dialog
if (!this.sqlView.getSQL()) return false;
this._modals.create(() =>
ViewFactory.createByTemplate(
templateApiDialog,
{
url: this._configModel.getSqlApiUrl(),
sql: this.sqlView.getSQL(),
schema: this.table.attributes.original_schema.slice(0, 5),
rows: this.table.dataModel.models
}
)
);
},
_initBinds: function () {
this.listenTo(this.model, 'change:bounds', function (model) {
this._updateTable();
});
this.listenTo(this.model, 'change:map', function (model) {
if (model.get('bounds')) {
this._updateTable();
}
});
this.authenticated_user.bind('change', this._onUserLogged, this);
this.add_related_model(this.authenticated_user);
this.listenToOnce(this.table, 'change:geometry_types', function (model) {
this.mapTab.setGeometry(model.get('geometry_types'));
});
},
// Get type of current view
// - It could be, dashboard, table or visualization
_getCurrentView: function () {
var pathname = location.pathname;
if (pathname.indexOf('/tables/') !== -1) {
return 'table';
}
if (pathname.indexOf('/viz/') !== -1) {
return 'visualization';
}
// Other case -> dashboard (datasets, visualizations,...)
return 'dashboard';
},
keyUp: function (e) {},
_onUserLogged: function () {
// Check if edit button should be visible
if (this.options.owner_username === this.authenticated_user.get('username')) {
this.$('.extra_options .edit').css('display', 'inline-block');
this.$('.extra_options .oneclick').css('display', 'none');
}
},
invalidateMap: function () {
this.mapTab.invalidateMap();
},
showTable: function () {
$('.pane_table').addClass('is-active');
$('.pane_map').removeClass('is-active');
this.tabs.activate('table');
},
showMap: function () {
$('.pane_table').removeClass('is-active');
$('.pane_map').addClass('is-active');
this.tabs.activate('map');
}
});