cartodb/lib/assets/javascripts/builder/components/privacy-dropdown/privacy-dropdown-view.js
2020-06-15 10:58:47 +08:00

363 lines
9.9 KiB
JavaScript
Executable File

var $ = require('jquery');
var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
var PrivacyDialogView = require('./privacy-dialog-view');
var PrivacyWarningView = require('builder/components/modals/privacy-warning/privacy-warning-view');
var PasswordDialogView = require('./password-dialog-view');
var TabPaneView = require('builder/components/tab-pane/tab-pane-view');
var TabPaneCollection = require('builder/components/tab-pane/tab-pane-collection');
var CustomListCollection = require('builder/components/custom-list/custom-list-collection');
var ModalsServiceModel = require('builder/components/modals/modals-service-model');
var template = require('./privacy-dropdown.tpl');
var templateTabPane = require('./tab-pane.tpl');
var TipsyTooltipView = require('builder/components/tipsy-tooltip-view');
var VisDefinitionModel = require('builder/data/vis-definition-model');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var ErrorDetailsView = require('builder/components/background-importer/error-details-view');
var ESCAPE_KEY_CODE = 27;
var REQUIRED_OPTS = [
'visDefinitionModel',
'userModel',
'privacyCollection',
'configModel',
'isOwner'
];
var PRIVACY_MAP = {
public: 'green',
link: 'orange',
password: 'orange-dark',
private: 'red'
};
module.exports = CoreView.extend({
events: {
'click .js-toggle': '_onToggleDialogClicked'
},
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
if (this._visDefinitionModel.isVisualization() && !this.options.mapcapsCollection) {
throw new Error('mapcapsCollection is required for visualizations');
}
this._triggerElementID = 'toggle' + this.cid;
this._modals = new ModalsServiceModel();
this.model = new Backbone.Model({
privacy: opts.visDefinitionModel.get('privacy'),
state: 'show'
});
this._onEscapePressed = this._onEscapePressed.bind(this);
this._onDocumentElementClicked = this._onDocumentElementClicked.bind(this);
if (this.options.ownerName) {
this._ownerName = this.options.ownerName;
}
if (this.options.mapcapsCollection) {
this._mapcapsCollection = this.options.mapcapsCollection;
}
this._configPrivacyCollection();
this._configPanes();
this._initBinds();
},
render: function () {
var privacy = this.model.get('privacy');
if (this.model.get('state') === 'error') {
privacy = this.options.visDefinitionModel.get('privacy');
}
var cssClass = PRIVACY_MAP[privacy.toLowerCase()];
var canChangePrivacy = this._canChangePrivacy(privacy);
this.clearSubViews();
this._hideDialog();
this.$el.html(template({
privacy: privacy,
cssClass: cssClass,
isLoading: this.model.get('state') === 'loading',
isOwner: this._isOwner,
canChangePrivacy: canChangePrivacy
}));
this._initViews();
return this;
},
_canChangePrivacy: function (privacy) {
var isIndividualUser = this.options.userModel.isIndividualUser();
var isMap = this.options.visDefinitionModel.isVisualization();
var hasRemainingPublicMaps = this.options.userModel.hasRemainingPublicMaps();
if (isIndividualUser && isMap && !hasRemainingPublicMaps && privacy === 'PRIVATE') {
return false;
}
return true;
},
_initBinds: function () {
this._customCollection.on('change:selected', function (menuItem) {
if (menuItem.get('disabled')) {
return;
}
if (menuItem.get('val') === 'password') {
this._showPasswordDialog();
} else {
this._onToggleDialogClicked();
this._setPrivacy(menuItem.get('val'));
}
}, this);
this.add_related_model(this._customCollection);
this.model.on('change:state', this.render, this);
this.add_related_model(this.model); // explicit
},
_makePrivacyDialog: function () {
return new PrivacyDialogView({
model: this.model,
collection: this._customCollection,
userModel: this._userModel,
configModel: this._configModel
});
},
_makePasswordDialog: function () {
return new PasswordDialogView({
onBack: this._showPrivacyDialog.bind(this),
onEdit: this._setPassword.bind(this)
});
},
_setPassword: function (password) {
if (password !== '') {
this._privacyCollection.passwordOption().set({
password: password
});
this.model.set({ password: password });
this._setPrivacy('password');
}
},
_setPrivacy: function (privacyStatus) {
var newPrivacyStatus = privacyStatus.toUpperCase();
this.model.set(
{ privacy: newPrivacyStatus },
{ silent: true }
);
if (this._shouldShowPrivacyWarning(newPrivacyStatus)) {
this._checkPrivacyChange(
newPrivacyStatus,
this._savePrivacy.bind(this),
this._discardPrivacyChange.bind(this)
);
} else {
this._savePrivacy();
}
},
_savePrivacy: function () {
var self = this;
var vis = this._visDefinitionModel;
this.model.set({ state: 'loading' });
this._privacyCollection.searchByPrivacy(this.model.get('privacy'))
.saveToVis(vis, {
success: function () {
self.model.set({state: 'show'});
},
error: function (req, resp) {
if (resp.responseText.indexOf('over account public map quota') !== -1) {
self._modals.create(function () {
return new ErrorDetailsView({
error: { errorCode: 8007 },
userModel: self._userModel,
configModel: self._configModel
});
});
}
self.model.set({state: 'error'});
}
});
},
_checkPrivacyChange: function (newPrivacyStatus, confirmCallback, dismissCallback) {
var self = this;
this._modals.create(function (modalModel) {
return new PrivacyWarningView({
modalModel: modalModel,
privacyType: newPrivacyStatus,
type: self._visDefinitionModel.isVisualization() ? 'visualization' : 'dataset',
onConfirm: confirmCallback,
onDismiss: dismissCallback
});
});
},
_discardPrivacyChange: function () {
var previousPrivacy = this.model.previous('privacy');
this.model.set('privacy', previousPrivacy, { silent: true });
this.model.set('state', 'show');
},
_shouldShowPrivacyWarning: function (privacyStatus) {
if (!this._userModel.canSelectPremiumOptions(this._visDefinitionModel)) {
return false;
}
var isPubliclyAvailable = VisDefinitionModel.isPubliclyAvailable(privacyStatus);
if (this._visDefinitionModel.isVisualization()) {
return !!this._mapcapsCollection.length && isPubliclyAvailable;
}
return isPubliclyAvailable;
},
_transformPrivacyOptions: function () {
return this._privacyCollection.map(function (item) {
return {
label: item.get('title'),
val: item.get('privacy').toLowerCase(),
disabled: item.get('disabled'),
selected: item.get('selected'),
renderOptions: {
cssClass: item.get('cssClass')
}
};
}).filter(Boolean);
},
_configPrivacyCollection: function () {
var models = this._transformPrivacyOptions();
this._customCollection = new CustomListCollection(models);
},
_configPanes: function () {
var self = this;
var tabPaneTabs = [{
createContentView: self._showNoneDialog
}, {
createContentView: self._makePrivacyDialog.bind(self)
}, {
createContentView: self._makePasswordDialog.bind(self)
}];
this._collectionPane = new TabPaneCollection(tabPaneTabs);
},
_showNoneDialog: function () {
return false;
},
_showPasswordDialog: function () {
this._collectionPane.at(2).set({selected: true});
},
_showPrivacyDialog: function () {
this._customCollection.each(function (m) {
m.set({selected: false}, {silent: true});
});
this._collectionPane.at(1).set({selected: true});
},
_onToggleDialogClicked: function () {
if (this._isDialogVisible()) {
this._hideDialog();
} else {
this._onMouseClick();
this._initDocumentBinds();
this._showPrivacyDialog();
}
},
_isDialogVisible: function () {
return this._collectionPane.at(0).get('selected') === false;
},
_hideDialog: function () {
this._destroyDocumentBinds();
this._collectionPane.at(0).set({selected: true});
},
_showDialog: function () {
this._showPrivacyDialog();
},
_initViews: function () {
var view = new TabPaneView({
collection: this._collectionPane,
template: templateTabPane,
mouseOverAction: this._onMouseClick.bind(this)
});
this.$('.js-dialog').append(view.render().$el);
this.addView(view);
this._privacyTooltip = new TipsyTooltipView({
el: this.$('.js-tooltip'),
gravity: 'w',
html: true,
title: function () {
return this._getPrivacyInfo();
}.bind(this)
});
this.addView(this._privacyTooltip);
},
_getPrivacyInfo: function () {
var privacyInfo = _t('change-privacy');
if (this._ownerName) {
privacyInfo = _t('dataset.privacy.info', { name: this._ownerName });
}
return privacyInfo;
},
_initDocumentBinds: function () {
$(document).on('keydown', this._onEscapePressed);
$(document).on('mousedown', this._onDocumentElementClicked);
},
_destroyDocumentBinds: function () {
$(document).off('keydown', this._onEscapePressed);
$(document).off('mousedown', this._onDocumentElementClicked);
},
_onEscapePressed: function (ev) {
if (ev.which === ESCAPE_KEY_CODE) {
this._hideDialog();
}
},
_onDocumentElementClicked: function (ev) {
var $el = $(ev.target);
if ($el.closest(this.$el).length === 0 && $el.closest($('#' + this._triggerElementID)).length === 0) {
this._hideDialog();
}
},
_onMouseClick: function () {
this._privacyTooltip.hideTipsy();
},
clean: function () {
this._destroyDocumentBinds();
CoreView.prototype.clean.apply(this);
}
});