Initial commit
This commit is contained in:
@@ -0,0 +1,436 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var Backbone = require('backbone');
|
||||
var template = require('./layer-header.tpl');
|
||||
var SyncInfoView = require('./sync-info/sync-info-view');
|
||||
var ContextMenuView = require('builder/components/context-menu/context-menu-view');
|
||||
var CustomListCollection = require('builder/components/custom-list/custom-list-collection');
|
||||
var VisTableModel = require('builder/data/visualization-table-model');
|
||||
var renameLayer = require('./operations/rename-layer');
|
||||
var DeleteLayerConfirmationView = require('builder/components/modals/remove-layer/delete-layer-confirmation-view');
|
||||
var InlineEditorView = require('builder/components/inline-editor/inline-editor-view');
|
||||
var ModalExportDataView = require('builder/components/modals/export-data/modal-export-data-view');
|
||||
var templateInlineEditor = require('./inline-editor.tpl');
|
||||
var zoomToData = require('builder/editor/map-operations/zoom-to-data');
|
||||
var TipsyTooltipView = require('builder/components/tipsy-tooltip-view');
|
||||
var IconView = require('builder/components/icon/icon-view');
|
||||
var checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
const { getSourceNode, nodeHasTradeArea, nodeHasSQLFunction } = require('builder/helpers/analysis-node-utils');
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'modals',
|
||||
'userActions',
|
||||
'layerDefinitionModel',
|
||||
'layerDefinitionsCollection',
|
||||
'configModel',
|
||||
'stateDefinitionModel',
|
||||
'editorModel',
|
||||
'userModel',
|
||||
'visDefinitionModel',
|
||||
'widgetDefinitionsCollection'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
module: 'layers:layer-header-view',
|
||||
|
||||
className: 'js-editorPanelHeader',
|
||||
|
||||
events: {
|
||||
'click .js-toggle-menu': '_onToggleContextMenuClicked',
|
||||
'click .js-zoom': '_onZoomClicked',
|
||||
'blur .js-input': '_hideRenameInput',
|
||||
'keyup .js-input': '_onKeyUpInput'
|
||||
},
|
||||
|
||||
initialize: function (opts) {
|
||||
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
|
||||
|
||||
this._sourceNodeModel = getSourceNode(this._getNodeModel());
|
||||
this._topQueryGeometryModel = null;
|
||||
|
||||
this._initVisTableModel();
|
||||
this._initViewState();
|
||||
this._bindEvents();
|
||||
this._onSourceChanged();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
|
||||
var tableName = '';
|
||||
var url = '';
|
||||
|
||||
if (this._visTableModel) {
|
||||
var tableModel = this._visTableModel.getTableModel();
|
||||
tableName = tableModel.getUnquotedName();
|
||||
url = this._visTableModel && this._visTableModel.datasetURL();
|
||||
}
|
||||
|
||||
this.$el.html(
|
||||
template({
|
||||
letter: this._layerDefinitionModel.get('letter'),
|
||||
id: this._getNodeModel().id,
|
||||
bgColor: this._layerDefinitionModel.getColor(),
|
||||
isTableSource: !!this._sourceNodeModel,
|
||||
url: url,
|
||||
tableName: tableName,
|
||||
title: this._layerDefinitionModel.getTableName().replace(/_/gi, ' '),
|
||||
alias: this._layerDefinitionModel.getName(),
|
||||
isEmpty: this._viewState.get('isLayerEmpty'),
|
||||
canBeGeoreferenced: this._viewState.get('canBeGeoreferenced')
|
||||
})
|
||||
);
|
||||
|
||||
this._showOrHideZoomVisibility();
|
||||
this._initViews();
|
||||
this._changeStyle();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_initVisTableModel: function () {
|
||||
if (this._sourceNodeModel) {
|
||||
var tableName = this._sourceNodeModel.get('table_name');
|
||||
this._visTableModel = new VisTableModel({
|
||||
id: tableName,
|
||||
table: {
|
||||
name: tableName
|
||||
}
|
||||
}, {
|
||||
configModel: this._configModel
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_initViewState: function () {
|
||||
this._viewState = new Backbone.Model({
|
||||
isLayerEmpty: false,
|
||||
hasGeom: true,
|
||||
canBeGeoreferenced: false
|
||||
});
|
||||
this._setViewStateValues();
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
this._addSyncInfo();
|
||||
|
||||
this._inlineEditor = new InlineEditorView({
|
||||
template: templateInlineEditor,
|
||||
renderOptions: {
|
||||
alias: this._layerDefinitionModel.getName()
|
||||
},
|
||||
onEdit: this._renameLayer.bind(this)
|
||||
});
|
||||
this.addView(this._inlineEditor);
|
||||
this.$('.js-header').append(this._inlineEditor.render().el);
|
||||
|
||||
var centerTooltip = new TipsyTooltipView({
|
||||
el: this._getZoom(),
|
||||
gravity: 'w',
|
||||
title: function () {
|
||||
return _t('editor.layers.options.center-map');
|
||||
}
|
||||
});
|
||||
|
||||
this.addView(centerTooltip);
|
||||
|
||||
var toggleMenuTooltip = new TipsyTooltipView({
|
||||
el: this._getToggleMenu(),
|
||||
gravity: 'w',
|
||||
title: function () {
|
||||
return _t('more-options');
|
||||
}
|
||||
});
|
||||
this.addView(toggleMenuTooltip);
|
||||
|
||||
if (this._viewState.get('isLayerEmpty') || this._viewState.get('canBeGeoreferenced')) {
|
||||
var warningIcon = new IconView({
|
||||
placeholder: this.$el.find('.js-warningIcon'),
|
||||
icon: 'warning'
|
||||
});
|
||||
warningIcon.render();
|
||||
this.addView(warningIcon);
|
||||
|
||||
var title = this._viewState.get('isLayerEmpty')
|
||||
? _t('editor.layers.layer.empty-layer')
|
||||
: _t('editor.layers.layer.geocode-tooltip');
|
||||
|
||||
var emptyLayerTooltip = new TipsyTooltipView({
|
||||
el: this.$el.find('.js-warningIcon'),
|
||||
gravity: 'w',
|
||||
title: function () {
|
||||
return title;
|
||||
}
|
||||
});
|
||||
this.addView(emptyLayerTooltip);
|
||||
}
|
||||
},
|
||||
|
||||
_getNodeModel: function () {
|
||||
return this._layerDefinitionModel.getAnalysisDefinitionNodeModel();
|
||||
},
|
||||
|
||||
_addSyncInfo: function () {
|
||||
var nodeModel = this._getNodeModel();
|
||||
|
||||
if (nodeModel && nodeModel.tableModel && nodeModel.tableModel.isSync()) {
|
||||
this._createSyncInfo(nodeModel.tableModel);
|
||||
}
|
||||
},
|
||||
|
||||
_createSyncInfo: function (tableModel) {
|
||||
var syncModel = tableModel.getSyncModel();
|
||||
this._syncInfoView = new SyncInfoView({
|
||||
modals: this._modals,
|
||||
syncModel: tableModel._syncModel,
|
||||
tableModel: tableModel,
|
||||
userModel: this._userModel
|
||||
});
|
||||
|
||||
this.addView(this._syncInfoView);
|
||||
this.$el.prepend(this._syncInfoView.render().el);
|
||||
|
||||
syncModel.bind('destroy', this._destroySyncInfo, this);
|
||||
this.add_related_model(syncModel);
|
||||
},
|
||||
|
||||
_destroySyncInfo: function () {
|
||||
this.removeView(this._syncInfoView);
|
||||
this._syncInfoView.clean();
|
||||
delete this._syncInfoView;
|
||||
},
|
||||
|
||||
_bindEvents: function () {
|
||||
if (this._tableNodeModel) {
|
||||
this._tableNodeModel.bind('change:synchronization', this.render, this);
|
||||
this.add_related_model(this._tableNodeModel);
|
||||
}
|
||||
|
||||
this._changeStyle = this._changeStyle.bind(this);
|
||||
this._layerDefinitionModel.bind('change:source', this._onSourceChanged, this);
|
||||
this._layerDefinitionModel.bind('change:source', this.render, this);
|
||||
this._editorModel.on('change:edition', this._changeStyle, this);
|
||||
this.add_related_model(this._editorModel);
|
||||
this.add_related_model(this._layerDefinitionModel);
|
||||
this.listenTo(this._viewState, 'change:hasGeom', this._showOrHideZoomVisibility);
|
||||
this.listenTo(this._viewState, 'change:isLayerEmpty change:canBeGeoreferenced', this.render);
|
||||
},
|
||||
|
||||
_onSourceChanged: function () {
|
||||
var nodeModel = this._getNodeModel();
|
||||
|
||||
if (this._topQueryGeometryModel !== null) {
|
||||
this._topQueryGeometryModel.unbind('change:simple_geom');
|
||||
}
|
||||
this._topQueryGeometryModel = nodeModel.queryGeometryModel.bind('change:simple_geom', this._setViewStateValues, this);
|
||||
this._setViewStateValues();
|
||||
},
|
||||
|
||||
_changeStyle: function () {
|
||||
var editing = this._editorModel.isEditing();
|
||||
this._getTitle().toggleClass('u-whiteTextColor', editing);
|
||||
this._getText().toggleClass('u-altTextColor', editing);
|
||||
this._getInlineEditor().toggleClass('u-mainTextColor', editing);
|
||||
this._getLink().toggleClass('u-whiteTextColor', editing);
|
||||
this._getBack().toggleClass('u-whiteTextColor', editing);
|
||||
this._getToggleMenu().toggleClass('is-white', editing);
|
||||
this._getZoom().toggleClass('is-white', editing);
|
||||
},
|
||||
|
||||
_getInlineEditor: function () {
|
||||
return this.$('.Inline-editor-input');
|
||||
},
|
||||
|
||||
_getTitle: function () {
|
||||
return this.$('.Editor-HeaderInfo-titleText .js-title');
|
||||
},
|
||||
|
||||
_getText: function () {
|
||||
return this.$('.Editor-breadcrumbItem');
|
||||
},
|
||||
|
||||
_getLink: function () {
|
||||
return this.$('.CDB-Text a');
|
||||
},
|
||||
|
||||
_getBack: function () {
|
||||
return this.$('.js-back');
|
||||
},
|
||||
|
||||
_getToggleMenu: function () {
|
||||
return this.$('.js-toggle-menu');
|
||||
},
|
||||
|
||||
_getZoom: function () {
|
||||
return this.$('.js-zoom');
|
||||
},
|
||||
|
||||
_onToggleContextMenuClicked: function (event) {
|
||||
if (this._hasContextMenu()) {
|
||||
this._hideContextMenu();
|
||||
} else {
|
||||
this._showContextMenu({
|
||||
x: event.pageX,
|
||||
y: event.pageY
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_hasContextMenu: function () {
|
||||
return this._menuView != null;
|
||||
},
|
||||
|
||||
_showContextMenu: function (position) {
|
||||
var menuItems = new CustomListCollection([{
|
||||
label: _t('editor.layers.options.rename'),
|
||||
val: 'rename-layer'
|
||||
}, {
|
||||
label: this._layerHidden() ? _t('editor.layers.options.show') : _t('editor.layers.options.hide'),
|
||||
val: 'toggle-layer'
|
||||
}, {
|
||||
label: _t('editor.layers.options.export'),
|
||||
val: 'export-data'
|
||||
}]);
|
||||
if (this._layerDefinitionModel.canBeDeletedByUser()) {
|
||||
menuItems.add({
|
||||
label: _t('editor.layers.options.delete'),
|
||||
val: 'delete-layer',
|
||||
destructive: true
|
||||
});
|
||||
}
|
||||
|
||||
var triggerElementID = 'context-menu-trigger-' + this._layerDefinitionModel.cid;
|
||||
this._getToggleMenu().attr('id', triggerElementID);
|
||||
this._menuView = new ContextMenuView({
|
||||
collection: menuItems,
|
||||
triggerElementID: triggerElementID,
|
||||
position: position
|
||||
});
|
||||
|
||||
menuItems.bind('change:selected', function (menuItem) {
|
||||
if (menuItem.get('val') === 'delete-layer') {
|
||||
this._confirmDeleteLayer();
|
||||
}
|
||||
if (menuItem.get('val') === 'rename-layer') {
|
||||
this._inlineEditor.edit();
|
||||
}
|
||||
if (menuItem.get('val') === 'toggle-layer') {
|
||||
var savingOptions = {
|
||||
shouldPreserveAutoStyle: true
|
||||
};
|
||||
this._layerDefinitionModel.toggleVisible();
|
||||
this._userActions.saveLayer(this._layerDefinitionModel, savingOptions);
|
||||
}
|
||||
if (menuItem.get('val') === 'export-data') {
|
||||
this._exportLayer();
|
||||
}
|
||||
}, this);
|
||||
|
||||
this._menuView.model.bind('change:visible', function (model, isContextMenuVisible) {
|
||||
if (this._hasContextMenu() && !isContextMenuVisible) {
|
||||
this._hideContextMenu();
|
||||
}
|
||||
}, this);
|
||||
|
||||
this._menuView.show();
|
||||
this.addView(this._menuView);
|
||||
},
|
||||
|
||||
_confirmDeleteLayer: function () {
|
||||
this._modals.create(function (modalModel) {
|
||||
var deleteLayerConfirmationView = new DeleteLayerConfirmationView({
|
||||
userActions: this._userActions,
|
||||
modals: this._modals,
|
||||
layerModel: this._layerDefinitionModel,
|
||||
modalModel: modalModel,
|
||||
visDefinitionModel: this._visDefinitionModel,
|
||||
widgetDefinitionsCollection: this._widgetDefinitionsCollection
|
||||
});
|
||||
|
||||
return deleteLayerConfirmationView;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_hideContextMenu: function () {
|
||||
this.removeView(this._menuView);
|
||||
this._menuView.clean();
|
||||
delete this._menuView;
|
||||
},
|
||||
|
||||
_exportLayer: function () {
|
||||
var nodeModel = this._getNodeModel();
|
||||
const { queryGeometryModel, querySchemaModel } = nodeModel;
|
||||
const canHideColumns = nodeHasTradeArea(nodeModel) &&
|
||||
!nodeHasSQLFunction(nodeModel);
|
||||
|
||||
this._modals.create(function (modalModel) {
|
||||
return new ModalExportDataView({
|
||||
fromView: 'layer',
|
||||
modalModel: modalModel,
|
||||
queryGeometryModel,
|
||||
querySchemaModel,
|
||||
canHideColumns,
|
||||
layerModel: this._layerDefinitionModel,
|
||||
configModel: this._configModel,
|
||||
filename: this._layerDefinitionModel.getName()
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_renameLayer: function () {
|
||||
var newName = this._inlineEditor.getValue();
|
||||
|
||||
if (newName !== '') {
|
||||
// Optimistic
|
||||
this._onSaveSuccess(newName);
|
||||
|
||||
renameLayer({
|
||||
newName: newName,
|
||||
userActions: this._userActions,
|
||||
layerDefinitionsCollection: this._layerDefinitionsCollection,
|
||||
layerDefinitionModel: this._layerDefinitionModel,
|
||||
onError: this._onSaveError.bind(this)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_onSaveSuccess: function (newName) {
|
||||
this.$('.js-title').text(newName).show();
|
||||
this.$('.js-title-editor').attr('title', newName);
|
||||
this._inlineEditor.hide();
|
||||
},
|
||||
|
||||
_onSaveError: function (oldName) {
|
||||
this.$('.js-title').text(oldName).show();
|
||||
this._inlineEditor.hide();
|
||||
},
|
||||
|
||||
_layerHidden: function () {
|
||||
return this._layerDefinitionModel.get('visible') === false;
|
||||
},
|
||||
|
||||
_onZoomClicked: function () {
|
||||
var nodeModel = this._getNodeModel();
|
||||
var query = nodeModel.querySchemaModel.get('query');
|
||||
zoomToData(this._configModel, this._stateDefinitionModel, query);
|
||||
},
|
||||
|
||||
_showOrHideZoomVisibility: function () {
|
||||
this._getZoom().toggle(this._viewState.get('hasGeom'));
|
||||
},
|
||||
|
||||
_setViewStateValues: function () {
|
||||
var nodeModel = this._getNodeModel();
|
||||
var isEmptyPromise = this._layerDefinitionModel.isEmptyAsync();
|
||||
var hasGeomPromise = nodeModel.queryGeometryModel.hasValueAsync();
|
||||
var canBeGeoreferencedPromise = this._layerDefinitionModel.canBeGeoreferenced();
|
||||
|
||||
Promise.all([isEmptyPromise, hasGeomPromise, canBeGeoreferencedPromise])
|
||||
.then(function (values) {
|
||||
this._viewState.set({
|
||||
isLayerEmpty: values[0],
|
||||
hasGeom: values[1],
|
||||
canBeGeoreferenced: values[2]
|
||||
});
|
||||
}.bind(this));
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user