cartodb-4.42/lib/assets/javascripts/builder/editor/editor-pane.js

444 lines
14 KiB
JavaScript
Raw Normal View History

2024-04-06 13:25:13 +08:00
var $ = require('jquery');
var Backbone = require('backbone');
var _ = require('underscore');
var CoreView = require('backbone/core-view');
var createTextLabelsTabPaneRouted = require('builder/components/tab-pane/create-text-labels-tab-pane-routed');
var Header = require('./editor-header.js');
var EditorTabPaneTemplate = require('./editor-tab-pane.tpl');
var EditorWidgetsView = require('./widgets/widgets-view');
var LayersView = require('./layers/layers-view');
var ScrollView = require('builder/components/scroll/scroll-view');
var PanelWithOptionsView = require('builder/components/view-options/panel-with-options-view');
var ShareButtonView = require('./layers/share-button-view');
var PublishView = require('builder/components/modals/publish/publish-view');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var Infobox = require('builder/components/infobox/infobox-factory');
var InfoboxModel = require('builder/components/infobox/infobox-model');
var InfoboxCollection = require('builder/components/infobox/infobox-collection');
var AppNotifications = require('builder/app-notifications');
var zoomToData = require('./map-operations/zoom-to-data');
var Router = require('builder/routes/router');
var REQUIRED_OPTS = [
'userActions',
'modals',
'configModel',
'userModel',
'editorModel',
'pollingModel',
'analysisDefinitionNodesCollection',
'layerDefinitionsCollection',
'privacyCollection',
'widgetDefinitionsCollection',
'mapcapsCollection',
'visDefinitionModel',
'stateDefinitionModel',
'selectedTabItem',
'mapStackLayoutModel',
'routeModel'
];
var LAYERS_TAB_NAME = 'layers';
var WIDGETS_TAB_NAME = 'widgets';
var MAX_LAYERS_REACHED = 'MAX_LAYERS_REACHED';
var ORIGIN_TABLE = 'table';
module.exports = CoreView.extend({
className: 'Editor-content',
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
this._initModels();
this._initBinds();
this._zoomToData = zoomToData; // For using Dependency Injection in specs
},
render: function () {
var self = this;
var count = this._getDataLayerCount();
var max = this._getMaxCount();
this.clearSubViews();
this.$el.empty();
var infoboxStates = [
this._getMaxLayerInfoBoxForCurrentUser(),
this._getUnknownErrorInfobox(),
this._getLimitInfobox('interactivity'),
this._getLimitInfobox('limit')
];
this._infoboxModel = new InfoboxModel({
state: null
});
var infoboxCollection = new InfoboxCollection(infoboxStates);
var tabPaneTabs = [{
name: LAYERS_TAB_NAME,
label: this._getTranslatedLayersLabel(count, max),
selected: this._selectedTabItem === LAYERS_TAB_NAME,
onClick: function () { Router.goToLayerList(); },
createContentView: function () {
return new PanelWithOptionsView({
className: 'Editor-content js-editorPanelContent',
editorModel: self._editorModel,
infoboxModel: self._infoboxModel,
infoboxCollection: infoboxCollection,
createContentView: function () {
return new ScrollView({
createContentView: function () {
var scrollViewInstance = this;
return new LayersView({
modals: self._modals,
userModel: self._userModel,
editorModel: self._editorModel,
configModel: self._configModel,
pollingModel: self._pollingModel,
userActions: self._userActions,
layerDefinitionsCollection: self._layerDefinitionsCollection,
analysisDefinitionNodesCollection: self._analysisDefinitionNodesCollection,
stateDefinitionModel: self._stateDefinitionModel,
widgetDefinitionsCollection: self._widgetDefinitionsCollection,
visDefinitionModel: self._visDefinitionModel,
showMaxLayerError: self._infoboxState.bind(self),
onNotificationCloseAction: scrollViewInstance._updateScrollWhenExist.bind(scrollViewInstance)
});
}
});
},
createActionView: function () {
return new ShareButtonView({
visDefinitionModel: self._visDefinitionModel,
onClickAction: self._share.bind(self)
});
}
});
}
}, {
name: 'widgets',
label: _t('editor.tab-pane.widgets.title-label'),
selected: this._selectedTabItem === WIDGETS_TAB_NAME,
onClick: function () { Router.goToWidgetList(); },
createContentView: function () {
return new PanelWithOptionsView({
className: 'Editor-content',
editorModel: self._editorModel,
infoboxModel: self._infoboxModel,
infoboxCollection: infoboxCollection,
createContentView: function () {
return new ScrollView({
createContentView: function () {
return new EditorWidgetsView({
userActions: self._userActions,
modals: self._modals,
layerDefinitionsCollection: self._layerDefinitionsCollection,
widgetDefinitionsCollection: self._widgetDefinitionsCollection,
analysisDefinitionNodesCollection: self._analysisDefinitionNodesCollection,
userModel: self._userModel,
configModel: self._configModel,
stackLayoutModel: self._mapStackLayoutModel
});
}
});
},
createActionView: function () {
return new ShareButtonView({
visDefinitionModel: self._visDefinitionModel,
onClickAction: self._share.bind(self)
});
}
});
}
}];
var header = new Header({
editorModel: self._editorModel,
mapcapsCollection: self._mapcapsCollection,
modals: self._modals,
visDefinitionModel: self._visDefinitionModel,
privacyCollection: self._privacyCollection,
clickPrivacyAction: self._share.bind(self),
onRemoveMap: self._onRemoveMap.bind(self),
configModel: self._configModel,
userModel: self._userModel
});
header.bind('export-image', this._onExportImage, this);
this.$el.append(header.render().$el);
this.addView(header);
var tabPaneOptions = {
tabPaneOptions: {
template: EditorTabPaneTemplate,
tabPaneItemOptions: {
tagName: 'li',
klassName: 'CDB-NavMenu-item'
}
},
tabPaneItemLabelOptions: {
tagName: 'button',
className: 'CDB-NavMenu-link u-upperCase'
}
};
this._mapTabPaneView = createTextLabelsTabPaneRouted(tabPaneTabs, tabPaneOptions);
this.$el.append(this._mapTabPaneView.render().$el);
this.addView(this._mapTabPaneView);
this._infoboxState();
return this;
},
_initModels: function () {
this._updatedModel = new Backbone.Model({
date: ''
});
},
_initBinds: function () {
this.listenTo(this._editorModel, 'change:edition', this._changeStyle);
this.listenTo(this._layerDefinitionsCollection, 'add', this._onLayerAdd);
this.listenTo(this._layerDefinitionsCollection, 'add remove', this._onLayerCountChange);
this.listenTo(AppNotifications.getCollection(), 'add', this._infoboxState);
this.listenTo(this._routeModel, 'change:currentRoute', this._handleRoute);
},
_handleRoute: function (routeModel) {
var currentRoute = routeModel.get('currentRoute');
if (!currentRoute) return;
var routeName = currentRoute[0];
if (routeName === WIDGETS_TAB_NAME) {
this._mapTabPaneView.setSelectedTabPaneByName(WIDGETS_TAB_NAME);
} else {
this._mapTabPaneView.setSelectedTabPaneByName(LAYERS_TAB_NAME);
}
},
_onLayerAdd: function (model, collection, options) {
if (options.origin && options.origin === ORIGIN_TABLE) {
var nodeModel = model.getAnalysisDefinitionNodeModel();
var query = nodeModel.querySchemaModel.get('query');
this._zoomToData(this._configModel, this._stateDefinitionModel, query);
}
this._visDefinitionModel.fetch();
},
_getMaxLayerTitle: function () {
return _t('editor.layers.max-layers-infowindow.title');
},
_getMaxLayerInfoBoxForCurrentUser: function () {
var infoboxOpts = {
type: 'alert',
title: this._getMaxLayerTitle()
};
var baseState = {
state: MAX_LAYERS_REACHED
};
// Open-source / local installation
if (this._configModel.isHosted()) {
infoboxOpts.body = _t('editor.layers.max-layers-infowindow.custom.body', { maxLayers: this._getMaxCount() });
infoboxOpts.action = { label: _t('editor.layers.max-layers-infowindow.custom.contact') };
baseState.onAction = function () { window.open(_t('editor.layers.max-layers-infowindow.custom.contact-url')); };
} else {
if (this._userModel.isInsideOrg()) {
if (this._userModel.isOrgAdmin()) {
infoboxOpts.body = _t('editor.layers.max-layers-infowindow.org-admin.body', { maxLayers: this._getMaxCount() });
infoboxOpts.action = { label: _t('editor.layers.max-layers-infowindow.org-admin.upgrade') };
} else {
infoboxOpts.body = _t('editor.layers.max-layers-infowindow.org.body', { maxLayers: this._getMaxCount() });
infoboxOpts.action = { label: _t('editor.layers.max-layers-infowindow.org.upgrade') };
}
baseState.onAction = function () { window.open('mailto:' + this._userModel.upgradeContactEmail()); };
} else {
baseState.onAction = function () { window.open(_t('editor.layers.max-layers-infowindow.pricing')); };
infoboxOpts.body = _t('editor.layers.max-layers-infowindow.regular.body', { maxLayers: this._getMaxCount() });
infoboxOpts.action = { label: _t('editor.layers.max-layers-infowindow.regular.upgrade') };
}
}
return _.extend(baseState, {
createContentView: function () {
return Infobox.createWithAction(infoboxOpts);
}
});
},
_getUnknownErrorInfobox: function () {
return {
state: 'unknown',
createContentView: function () {
return Infobox.createWithAction({
type: 'alert',
title: _t('editor.messages.generic-error.title'),
body: _t('editor.messages.generic-error.body'),
className: 'fs-unknown-tile-error'
});
}
};
},
_getLimitInfobox: function (type) {
var infoboxOpts = {
type: 'alert',
title: _t('editor.messages.' + type + '.title'),
body: _t('editor.messages.' + type + '.body')
};
var baseState = {
state: type,
onClose: function () {
AppNotifications.muteByType(type);
this._infoboxModel.set('state', null);
}.bind(this)
};
if (!this._configModel.isHosted()) {
infoboxOpts.action = {
label: _t('editor.messages.' + type + '.cta.label'),
type: 'secondary'
};
baseState.onAction = function () {
window.open(_t('editor.messages.' + type + '.cta.url'));
};
infoboxOpts.body = _t('editor.messages.' + type + '.body') + _t('editor.messages.' + type + '.try_to');
}
return _.extend(baseState, {
createContentView: function () {
return Infobox.createWithAction(infoboxOpts);
}
});
},
_onLayerCountChange: function () {
var count = this._getDataLayerCount();
var max = this._getMaxCount();
var layersModel = this._mapTabPaneView.getTabPaneCollection().find(function (model) {
return model.get('name') === LAYERS_TAB_NAME;
});
layersModel.set('label', this._getTranslatedLayersLabel(count, max));
if (count === max) {
this._infoboxState();
} else {
this._infoboxModel.set('state', null);
}
},
_infoboxState: function () {
var count = this._getDataLayerCount();
var max = this._getMaxCount();
var hasLimitError = AppNotifications.getByType('limit');
var hasUnknownError = AppNotifications.getByType('unknown');
var hasInteractivityError = AppNotifications.getByType('interactivity');
if (hasLimitError) {
this._infoboxModel.set('state', 'limit');
} else if (hasInteractivityError) {
this._infoboxModel.set('state', 'interactivity');
} else if (hasUnknownError) {
this._infoboxModel.set('state', 'unknown');
} else if (count === max) {
this._infoboxModel.set('state', MAX_LAYERS_REACHED);
} else {
this._infoboxModel.set('state', null);
}
},
_onExportImage: function () {
this.trigger('export-image', this);
},
_onRemoveMap: function () {
window.location = this._userModel.get('base_url');
},
_getDataLayerCount: function () {
return this._layerDefinitionsCollection.getNumberOfDataLayers();
},
_getMaxCount: function () {
return this._userModel.get('limits').max_layers;
},
_getTranslatedLayersLabel: function (count, max) {
return _t('editor.tab-pane.layers.title-label', {
count: count,
maxCount: max
});
},
_share: function () {
var self = this;
this._modals.create(function (modalModel) {
return new PublishView({
mapcapsCollection: self._mapcapsCollection,
modalModel: modalModel,
visDefinitionModel: self._visDefinitionModel,
privacyCollection: self._privacyCollection,
userModel: self._userModel,
configModel: self._configModel,
isOwner: true
});
}, {
breadcrumbsEnabled: true
});
},
_changeStyle: function (m) {
this.$el.toggleClass('is-dark');
this._mapTabPaneView.changeStyleMenu(m);
},
_setUpdateFromCreation: function () {
this._updatedModel.set({date: this._visDefinitionModel.get('created_at')});
},
_setUpdateFromMapcap: function (mapcaps) {
this._updatedModel.set({date: mapcaps[0].created_at});
},
_getMapcaps: function () {
var updateFromCreation = this._setUpdateFromCreation.bind(this);
var updateFromMapcap = this._setUpdateFromMapcap.bind(this);
var url = this._visDefinitionModel.mapcapsURL();
var data = {
api_key: this._configModel.get('api_key')
};
$.get(url, data)
.done(function (data) {
if (data.length > 0) {
updateFromMapcap(data);
} else {
updateFromCreation();
}
})
.fail(function () {
updateFromCreation();
});
}
});