Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions
@@ -0,0 +1,4 @@
<h2 class="Inline-editor">
<div class="CDB-Text CDB-Size-huge is-light u-ellipsis js-title Inline-editor-text"><%- title %></div>
<input type="text" name="text" class="Inline-editor-input Inline-editor-input--small CDB-Text CDB-InputText js-input" value="<%- title %>" readonly>
</h2>
@@ -0,0 +1,123 @@
var _ = require('underscore');
var Backbone = require('backbone');
var WidgetDefinitionModel = require('builder/data/widget-definition-model');
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
var FillConstants = require('builder/components/form-components/_constants/_fill');
module.exports = Backbone.Model.extend({
initialize: function (attrs, options) {
var o = [
{
val: true,
label: _t('editor.widgets.widgets-form.style.yes')
}, {
val: false,
label: _t('editor.widgets.widgets-form.style.no')
}
];
this.schema = {
sync_on_bbox_change: {
type: 'Radio',
title: _t('editor.widgets.widgets-form.style.sync_on_bbox_change'),
options: o
}
};
},
_addAllStyleSchemaAttributes: function () {
var customType = this.get('type') === 'category' ? 'categories' : 'ramp';
var styleAttrs = {
widget_style_definition: {
type: 'Fill',
title: _t('editor.widgets.widgets-form.style.fill'),
options: [],
configModel: this._configModel,
modals: this._modals,
userModel: this._userModel,
dialogMode: DialogConstants.Mode.FLOAT,
editorAttrs: {
color: {
hidePanes: [FillConstants.Panes.BY_VALUE],
disableOpacity: true
}
}
}
};
if (this.get('auto_style_allowed')) {
var editorAttrs = {
color: {
hidePanes: [FillConstants.Panes.FIXED]
}
};
if (customType === 'categories') {
editorAttrs.color.hideTabs = [
FillConstants.Tabs.BINS,
FillConstants.Tabs.QUANTIFICATION
];
}
styleAttrs = _.extend(styleAttrs, {
auto_style_definition: {
type: 'EnablerEditor',
title: '',
label: _t('editor.widgets.widgets-form.style.custom-colors'),
help: _t('editor.widgets.widgets-form.style.custom-help'),
editor: {
type: 'Fill',
title: '',
options: [this.get('column')],
dialogMode: DialogConstants.Mode.FLOAT,
query: 'query',
configModel: this._configModel,
modals: this._modals,
userModel: this._userModel,
editorAttrs: editorAttrs
}
}
});
} else {
styleAttrs = _.extend(styleAttrs, {
auto_style_definition: {
type: 'Text',
title: _t('editor.widgets.widgets-form.style.custom-colors'),
help: _t('editor.widgets.widgets-form.style.custom-disabled'),
disabled: true
}
});
}
this.schema = _.extend(this.schema, styleAttrs);
},
parse: function (r) {
var attrs = _.defaults(
{
sync_on_bbox_change: r.sync_on_bbox_change ? 'true' : 'false'
},
r
);
return attrs;
},
changeWidgetDefinitionModel: function (widgetDefinitionModel) {
var attrs = _.defaults(
{
sync_on_bbox_change: this.get('sync_on_bbox_change') === 'true'
},
this._prepareAttributesForWidgetDefinition()
);
if (attrs.auto_style_definition !== '' && _.isEmpty(attrs.auto_style_definition)) {
attrs.auto_style_definition = WidgetDefinitionModel.getDefaultAutoStyle(widgetDefinitionModel.get('type'), widgetDefinitionModel.get('column'));
}
widgetDefinitionModel.set(attrs);
},
_prepareAttributesForWidgetDefinition: function () {
return this.attributes;
}
});
@@ -0,0 +1,122 @@
var _ = require('underscore');
var WidgetsFormBaseSchema = require('./widgets-form-base-schema-model');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
var REQUIRED_OPTS = [
'columnOptionsFactory',
'modals',
'configModel',
'userModel'
];
module.exports = WidgetsFormBaseSchema.extend({
defaults: {
schema: {},
aggregate: {
attribute: '',
operator: 'count'
}
},
initialize: function (attrs, opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
this.on('change:aggregate', this._updateAggregation, this);
this.on('change:column', this.updateSchema, this);
this._updateAggregation();
WidgetsFormBaseSchema.prototype.initialize.apply(this, arguments);
},
getFields: function () {
var fields = ['column', 'aggregate', 'prefix', 'suffix'];
return {
data: fields.join(','),
style: ['sync_on_bbox_change', 'widget_style_definition', 'auto_style_definition']
};
},
_updateAggregation: function () {
var aggregate = this.get('aggregate');
if (aggregate === undefined) {
this.set({
aggregation: 'count',
aggregation_column: ''
});
} else {
this.set({
aggregation_column: aggregate.attribute,
aggregation: aggregate.operator
});
}
this.updateSchema();
},
updateSchema: function () {
var columnOptions = this._columnOptionsFactory.create(this.get('column'));
var helpMsg = this._columnOptionsFactory.unavailableColumnsHelpMessage();
var aggregationOptions = _.filter(columnOptions, function (column) {
return column.type === 'number';
});
this.schema = _.extend(this.schema, {
column: {
type: 'Select',
title: _t('editor.widgets.widgets-form.data.aggregate-by'),
options: columnOptions,
help: helpMsg,
dialogMode: DialogConstants.Mode.FLOAT,
editorAttrs: {
disabled: this._columnOptionsFactory.areColumnsUnavailable()
}
},
aggregate: {
type: 'Operators',
title: _t('editor.widgets.widgets-form.data.operation'),
options: aggregationOptions,
dialogMode: DialogConstants.Mode.FLOAT,
editorAttrs: {
showSearch: false
}
},
suffix: {
type: 'EnablerEditor',
title: '',
label: _t('editor.widgets.widgets-form.data.suffix'),
editor: {
type: 'Text'
}
},
prefix: {
type: 'EnablerEditor',
title: '',
label: _t('editor.widgets.widgets-form.data.prefix'),
editor: {
type: 'Text'
}
}
});
this._addAllStyleSchemaAttributes();
},
canSave: function () {
var aggregation = this.get('aggregation');
var aggregationColumn = this.get('aggregation_column');
var canSave = false;
if (aggregation === 'count') {
canSave = true;
} else {
canSave = !!(aggregation && aggregationColumn);
}
return canSave;
}
});
@@ -0,0 +1,102 @@
var _ = require('underscore');
var WidgetsFormBaseSchema = require('./widgets-form-base-schema-model');
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
module.exports = WidgetsFormBaseSchema.extend({
defaults: {
schema: {},
aggregate: {
attribute: '',
operator: 'count'
}
},
initialize: function (attrs, opts) {
if (!opts.columnOptionsFactory) throw new Error('columnOptionsFactory is required');
this._columnOptionsFactory = opts.columnOptionsFactory;
this.listenTo(this, 'change:aggregate', this._updateAggregate);
this._updateAggregate();
WidgetsFormBaseSchema.prototype.initialize.apply(this, arguments);
},
parse: function (r) {
r.aggregate = {
attribute: r.column,
operator: r.operation
};
return r;
},
getFields: function () {
return {
data: 'aggregate,prefix,suffix,description',
style: 'sync_on_bbox_change'
};
},
_updateAggregate: function () {
var aggregate = this.get('aggregate');
this.set({
column: aggregate.attribute,
operation: aggregate.operator
});
this.updateSchema();
},
updateSchema: function () {
var columnOptions = this._columnOptionsFactory.create(this.get('column'), this._isNumberType);
this.schema = _.extend(this.schema, {
aggregate: {
type: 'Operators',
title: _t('editor.widgets.widgets-form.data.operation'),
options: columnOptions,
dialogMode: DialogConstants.Mode.FLOAT,
editorAttrs: {
showSearch: false
}
},
suffix: {
type: 'EnablerEditor',
title: '',
label: _t('editor.widgets.widgets-form.data.suffix'),
editor: {
type: 'Text'
}
},
prefix: {
type: 'EnablerEditor',
title: '',
label: _t('editor.widgets.widgets-form.data.prefix'),
editor: {
type: 'Text'
}
},
description: {
type: 'EnablerEditor',
title: '',
label: _t('editor.widgets.widgets-form.style.description'),
editor: {
type: 'TextArea'
}
}
});
},
canSave: function () {
var column = this.get('column');
var operation = this.get('operation');
return operation === 'count' || !!column;
},
_isNumberType: function (m) {
return m.get('type') === 'number';
}
});
@@ -0,0 +1,69 @@
var _ = require('underscore');
var WidgetsFormBaseSchema = require('./widgets-form-base-schema-model');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
var NUMBER_TYPE = 'number';
var REQUIRED_OPTS = [
'columnOptionsFactory',
'modals',
'configModel',
'userModel'
];
module.exports = WidgetsFormBaseSchema.extend({
initialize: function (attrs, opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
WidgetsFormBaseSchema.prototype.initialize.apply(this, arguments);
},
getFields: function () {
return {
data: ['column', 'bins'],
style: ['sync_on_bbox_change', 'widget_style_definition', 'auto_style_definition']
};
},
updateSchema: function () {
var columnOptions = this._columnOptionsFactory.create(this.get('column'), this._isNumberType);
var helpMsg = this._columnOptionsFactory.unavailableColumnsHelpMessage();
this.schema = _.extend(this.schema, {
column: {
title: _t('editor.widgets.widgets-form.data.column'),
type: 'Select',
help: helpMsg,
options: columnOptions,
dialogMode: DialogConstants.Mode.FLOAT,
editorAttrs: {
disabled: this._columnOptionsFactory.areColumnsUnavailable()
},
validators: [{
type: 'columnType',
columnsCollection: this._columnOptionsFactory._querySchemaModel.columnsCollection,
columnType: 'number'
}]
},
bins: {
title: _t('editor.widgets.widgets-form.data.bins'),
type: 'Number',
validators: ['required', {
type: 'interval',
min: 2,
max: 30
}]
}
});
this._addAllStyleSchemaAttributes();
},
canSave: function () {
return !!this.get('column');
},
_isNumberType: function (m) {
return m.get('type') === NUMBER_TYPE;
}
});
@@ -0,0 +1,206 @@
var _ = require('underscore');
var WidgetsFormBaseSchema = require('./widgets-form-base-schema-model');
var TimeSeriesQueryModel = require('builder/editor/widgets/time-series-query-model');
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
var FillConstants = require('builder/components/form-components/_constants/_fill');
var timezones = require('builder/data/timezones');
var moment = require('moment');
var checkAndBuildOpts = require('builder/helpers/required-opts');
require('moment-timezone');
var REQUIRED_OPTS = [
'columnOptionsFactory',
'configModel',
'querySchemaModel'
];
module.exports = WidgetsFormBaseSchema.extend({
defaults: {
schema: {},
bins: 48,
timezone: '',
offset: 0
},
initialize: function (attrs, opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
WidgetsFormBaseSchema.prototype.initialize.apply(this, arguments);
this._timeSeriesQueryModel = new TimeSeriesQueryModel({
column: this.get('column')
}, {
configModel: this._configModel,
querySchemaModel: this._querySchemaModel
});
this._initBinds();
},
_initBinds: function () {
this.on('change:column', this._onColumnChanged, this);
this.listenTo(this._timeSeriesQueryModel, 'change:buckets', this.updateSchema);
},
getFields: function () {
var columnType = this._getColumnType();
var data = ['column'];
if (columnType === 'date') {
data.push('timezone', 'aggregation');
} else {
data.push('bins');
}
return {
data: data,
style: ['sync_on_bbox_change', 'widget_style_definition']
};
},
updateSchema: function () {
var columnOptions = this._columnOptionsFactory.create(this.get('column'), this._isNumberOrDateType.bind(this));
var helpMsg = this._columnOptionsFactory.unavailableColumnsHelpMessage();
this.schema = _.extend(this.schema, {
column: {
title: _t('editor.widgets.widgets-form.data.column'),
type: 'Select',
help: helpMsg,
options: columnOptions,
dialogMode: DialogConstants.Mode.FLOAT,
editorAttrs: {
disabled: this._columnOptionsFactory.areColumnsUnavailable()
}
},
widget_style_definition: {
type: 'Fill',
title: _t('editor.widgets.widgets-form.style.fill'),
options: [],
dialogMode: DialogConstants.Mode.FLOAT,
editorAttrs: {
color: {
hidePanes: [FillConstants.Panes.BY_VALUE],
disableOpacity: true
}
}
}
});
var columnType = this._getColumnType();
if (columnType === 'date') {
var aggregationOptions = this._timeSeriesQueryModel.getFilteredBuckets();
var sortedTimezoneOptions = this._getSortedTimezoneOptions(timezones);
this.schema = _.extend(this.schema, {
aggregation: {
title: _t('editor.widgets.widgets-form.data.bins'),
type: 'Select',
placeholder: _t('editor.widgets.widgets-form.data.select-bucket'),
searchPlaceholder: _t('editor.widgets.widgets-form.data.search-by-bucket'),
options: aggregationOptions,
dialogMode: DialogConstants.Mode.FLOAT,
loading: _.isEmpty(aggregationOptions)
},
timezone: {
title: _t('editor.widgets.widgets-form.data.timezone'),
type: 'Select',
options: sortedTimezoneOptions,
dialogMode: DialogConstants.Mode.FLOAT
}
});
} else {
this.schema = _.extend(this.schema, {
bins: {
title: _t('editor.widgets.widgets-form.data.bins'),
type: 'Number',
validators: ['required', {
type: 'interval',
min: 0,
max: 256
}]
}
});
}
this.trigger('changeSchema');
},
canSave: function () {
return this.get('column');
},
_isDateType: function (model) {
return model.get('type') === 'date';
},
_isNumberType: function (model) {
return model.get('type') === 'number';
},
_isNumberOrDateType: function (model) {
return this._isDateType(model) || this._isNumberType(model);
},
_onColumnChanged: function () {
this.set({
aggregation: undefined
}, { silent: true });
this._timeSeriesQueryModel.set('column', this.get('column'));
this.set('column_type', this._getColumnType());
this.updateSchema();
},
_getColumnType: function () {
var column;
if (this._querySchemaModel.isFetched()) {
column = this._querySchemaModel.columnsCollection.findWhere({ name: this.get('column') });
}
return column && column.get('type');
},
_prepareAttributesForWidgetDefinition: function () {
var attrs = this.toJSON();
if (this._getColumnType() === 'date') {
attrs.bins = undefined;
attrs.offset = moment.tz(attrs.timezone).utcOffset() * 60;
} else {
attrs.aggregation = undefined;
attrs.timezone = undefined;
attrs.offset = undefined;
}
return attrs;
},
_getSortedTimezoneOptions: function (timezones) {
return _.chain(timezones)
.reduce(function (memo, tz) {
var name = tz.name;
memo.push({
label: tz.label,
name: name,
offset: moment.tz(name).utcOffset()
});
return memo;
}, [])
.sortBy('offset')
.reduce(function (memo, tz) {
var name = tz.name;
var timezone = tz.offset ? moment.tz(name).format('Z') : '';
memo.push({
label: '(GMT' + timezone + ') ' + tz.label,
val: name
});
return memo;
}, [])
.value();
}
});
@@ -0,0 +1,133 @@
var CoreView = require('backbone/core-view');
var template = require('./widget-header.tpl');
var InlineEditorView = require('builder/components/inline-editor/inline-editor-view');
var VisTableModel = require('builder/data/visualization-table-model');
var templateInlineEditor = require('./inline-editor.tpl');
var ContextMenuFactory = require('builder/components/context-menu-factory-view');
var WidgetsService = require('builder/editor/widgets/widgets-service');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var analyses = require('builder/data/analyses');
var REQUIRED_OPTS = [
'layerDefinitionModel',
'userActions',
'stackLayoutModel',
'configModel'
];
module.exports = CoreView.extend({
events: {
'click .js-toggle-menu': '_onToggleContextMenuClicked'
},
initialize: function (opts) {
if (!this.model) throw new Error('model is required');
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
this._sourceNode = this._getSourceNode();
if (this._sourceNode) {
var tableName = this._sourceNode.get('table_name');
this._visTableModel = new VisTableModel({
id: tableName,
table: {
name: tableName
}
}, {
configModel: this._configModel
});
}
},
render: function () {
var widgetTitle = this.model.get('title');
var source = this.model.get('source');
var analysisNode = this._layerDefinitionModel.findAnalysisDefinitionNodeModel(source);
var layerName = analysisNode.isSourceType()
? this._layerDefinitionModel.getTableName()
: this._layerDefinitionModel.getName();
this.$el.html(
template({
title: widgetTitle,
source: source,
color: this._layerDefinitionModel.get('color'),
layerName: layerName,
nodeTitle: analyses.short_title(analysisNode),
isSourceType: analysisNode.isSourceType(),
url: this._visTableModel ? this._visTableModel.datasetURL() : ''
})
);
this._initViews();
return this;
},
_initViews: function () {
var widgetTitle = this.model.get('title');
this._inlineEditor = new InlineEditorView({
template: templateInlineEditor,
renderOptions: {
title: widgetTitle
},
onEdit: this._renameWidget.bind(this)
});
this.$('.js-header').append(this._inlineEditor.render().el);
this.addView(this._inlineEditor);
var menuItems = [{
label: _t('editor.widgets.options.rename'),
val: 'rename-widget',
action: this._onRenameWidget.bind(this)
}, {
label: _t('editor.widgets.options.remove'),
val: 'delete-widget',
destructive: true,
action: this._confirmDeleteWidget.bind(this)
}];
this._contextMenuFactory = new ContextMenuFactory({
menuItems: menuItems
});
this.$('.js-context-menu').append(this._contextMenuFactory.render().el);
this.addView(this._contextMenuFactory);
},
_getSourceNode: function () {
var nodeModel = this._layerDefinitionModel.getAnalysisDefinitionNodeModel();
var source;
if (nodeModel.get('type') === 'source') {
source = nodeModel;
} else {
var primarySource = nodeModel.getPrimarySource();
if (primarySource && primarySource.get('type') === 'source') {
source = primarySource;
}
}
return source;
},
_onRenameWidget: function () {
this._inlineEditor.edit();
},
_renameWidget: function () {
var newName = this._inlineEditor.getValue();
if (newName !== '' && newName !== this.model.get('title')) {
this.model.set({title: newName});
this._userActions.saveWidget(this.model);
this.$('.js-title').text(newName).show();
this._inlineEditor.hide();
}
},
_confirmDeleteWidget: function () {
WidgetsService.removeWidget(this.model);
}
});
@@ -0,0 +1,39 @@
<ul class="Editor-breadcrumb">
<li class="Editor-breadcrumbItem CDB-Text CDB-Size-medium u-actionTextColor">
<button class="js-back">
<i class="CDB-IconFont CDB-IconFont-arrowPrev Size-large u-rSpace"></i>
<span class="Editor-breadcrumbLink"><%- _t('back') %></span>
</button>
</li>
<li class="Editor-breadcrumbItem CDB-Text CDB-Size-medium"><span class="Editor-breadcrumbSep"> / </span> <%- _t('editor.widgets.breadcrumb.widget-options') %></li>
</ul>
<div class="Editor-HeaderInfoEditor">
<div class="Editor-HeaderInfo-inner Editor-HeaderInfo-inner--wide">
<div class="Editor-HeaderInfo-title js-context-menu">
<div class="Editor-HeaderInfo-titleText js-header"></div>
</div>
<div class="Editor-HeaderInfo u-flex u-alignCenter">
<span class="CDB-Text CDB-Size-small is-semibold u-bSpace--s u-upperCase" style="color: <%- color %>;">
<%- source %>
</span>
<% if (!isSourceType) { %>
<span class="CDB-Text CDB-Size-small u-lSpace--s u-flex" style="color: <%- color %>;">
<i class="CDB-IconFont CDB-Size-small CDB-IconFont-ray"></i>
</span>
<% } %>
<span class="CDB-Text CDB-Size-small u-lSpace">
<%= nodeTitle %>
</span>
<span class="CDB-Text CDB-Size-small u-altTextColor u-ellipsis u-lSpace" title="<%= layerName %>">
<%= layerName %>
</span>
</div>
</div>
</div>
@@ -0,0 +1,44 @@
/**
* Object to generate column options for a current state of a query schema model
*/
var F = function (querySchemaModel) {
this._querySchemaModel = querySchemaModel;
};
F.prototype.areColumnsUnavailable = function () {
var status = this._querySchemaModel.get('status');
return status === 'fetching' || status === 'unavailable';
};
F.prototype.unavailableColumnsHelpMessage = function () {
if (this._querySchemaModel.get('status') === 'unavailable') {
return _t('editor.widgets.widgets-form.data.columns-unavailable');
}
};
F.prototype.create = function (currentVal, columnFilter) {
columnFilter = columnFilter || function () {
return true;
};
switch (this._querySchemaModel.get('status')) {
case 'fetching':
return [{val: _t('editor.widgets.widgets-form.data.loading')}];
case 'unavailable':
return [{val: currentVal}];
default:
return this._querySchemaModel
.columnsCollection
.filter(columnFilter)
.map(function (m) {
var columnName = m.get('name');
return {
val: columnName,
label: columnName,
type: m.get('type')
};
});
}
};
module.exports = F;
@@ -0,0 +1,77 @@
var CoreView = require('backbone/core-view');
var WidgetsFormView = require('./widgets-form-view');
var WidgetHeaderView = require('./widget-header.js');
var ScrollView = require('builder/components/scroll/scroll-view');
var Router = require('builder/routes/router');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var REQUIRED_OPTS = [
'userActions',
'widgetDefinitionModel',
'modals',
'analysisDefinitionNodesCollection',
'layerDefinitionsCollection',
'stackLayoutModel',
'configModel',
'userModel'
];
/**
* View to render all necessary for the widget form
*/
module.exports = CoreView.extend({
events: {
'click .js-back': '_goBack'
},
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
},
render: function () {
this.clearSubViews();
this._initViews();
return this;
},
_initViews: function () {
var self = this;
var nodeId = self._widgetDefinitionModel.get('source');
var analysisDefinitionNodeModel = self._analysisDefinitionNodesCollection.get(nodeId);
var header = new WidgetHeaderView({
layerDefinitionModel: this._layerDefinitionsCollection.get(this._widgetDefinitionModel.get('layer_id')),
model: this._widgetDefinitionModel,
modals: this._modals,
userActions: this._userActions,
stackLayoutModel: this._stackLayoutModel,
configModel: this._configModel
});
this.$el.append(header.render().$el);
this.addView(header);
var view = new ScrollView({
createContentView: function () {
return new WidgetsFormView({
userActions: self._userActions,
widgetDefinitionModel: self._widgetDefinitionModel,
querySchemaModel: analysisDefinitionNodeModel.querySchemaModel,
modals: self._modals,
configModel: self._configModel,
userModel: self._userModel
});
}
});
this.$el.append(view.render().$el);
this.addView(view);
},
_goBack: function () {
Router.goToPreviousRoute({
fallback: 'widgets'
});
}
});
@@ -0,0 +1,71 @@
var _ = require('underscore');
var WidgetsFormColumnOptionsFactory = require('./widgets-form-column-options-factory');
var dataMap = {
category: {
labelTranslationKey: 'editor.widgets.widgets-form.type.category',
iconTemplate: require('builder/editor/widgets/widget-icon-category.tpl'),
Class: require('./schema/widgets-form-category-schema-model')
},
formula: {
labelTranslationKey: 'editor.widgets.widgets-form.type.formula',
iconTemplate: require('builder/editor/widgets/widget-icon-formula.tpl'),
Class: require('./schema/widgets-form-formula-schema-model'),
checkIfValid: function (querySchemaModel) {
return querySchemaModel.columnsCollection.any(function (m) {
return m.get('type') === 'number';
});
}
},
histogram: {
labelTranslationKey: 'editor.widgets.widgets-form.type.histogram',
iconTemplate: require('builder/editor/widgets/widget-icon-histogram.tpl'),
Class: require('./schema/widgets-form-histogram-schema-model'),
checkIfValid: function (querySchemaModel) {
return querySchemaModel.columnsCollection.any(function (m) {
return m.get('type') === 'number';
});
}
},
'time-series': {
labelTranslationKey: 'editor.widgets.widgets-form.type.time_series',
iconTemplate: require('builder/editor/widgets/widget-icon-timeSeries.tpl'),
Class: require('./schema/widgets-form-time-series-schema-model'),
checkIfValid: function (querySchemaModel) {
return querySchemaModel.columnsCollection.any(function (m) {
return m.get('type') === 'date' || m.get('type') === 'number';
});
}
}
};
module.exports = {
createWidgetFormModel: function (options) {
var widgetDefinitionModel = options.widgetDefinitionModel;
var widgetType = widgetDefinitionModel.get('type');
var Klass = dataMap[widgetType].Class;
return new Klass(widgetDefinitionModel.attributes, {
parse: true, // in case the raw attributes needs to be adapted to the expected form types, e.g. timestamp => Date
columnOptionsFactory: new WidgetsFormColumnOptionsFactory(options.querySchemaModel),
userModel: options.userModel,
modals: options.modals,
configModel: options.configModel,
querySchemaModel: options.querySchemaModel
});
},
getDataTypes: function (querySchemaModel) {
return _.reduce(dataMap, function (memo, val, key) {
if (val.checkIfValid ? val.checkIfValid(querySchemaModel) : true) {
memo.push({
iconTemplate: val.iconTemplate,
value: key,
label: _t(val.labelTranslationKey)
});
}
return memo;
}, []);
}
};
@@ -0,0 +1,124 @@
var _ = require('underscore');
var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
var WidgetFormFactory = require('./widgets-form-factory');
var template = require('./widgets-form-fields.tpl');
require('builder/components/form-components/index');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var REQUIRED_OPTS = [
'userActions',
'widgetDefinitionModel',
'querySchemaModel',
'modals',
'configModel',
'userModel'
];
/**
* View of form to edit a widget definition's data
*
*/
module.exports = CoreView.extend({
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
var widgetOptions = {
widgetDefinitionModel: this._widgetDefinitionModel,
querySchemaModel: this._querySchemaModel,
modals: this._modals,
userModel: this._userModel,
configModel: this._configModel
};
this._widgetFormModel = WidgetFormFactory.createWidgetFormModel(widgetOptions);
this._widgetFormModel.updateSchema();
this._debounceSaveWidget = _.debounce(this._saveWidget.bind(this), 500);
this._initBinds();
},
render: function () {
this.clearSubViews();
this._removeForm();
this.$el.empty();
this._initViews();
return this;
},
_initBinds: function () {
this._widgetFormModel.bind('change:column change:aggregation changeSchema', this.render, this);
this._widgetFormModel.bind('change', this._onFormChange, this);
this.add_related_model(this._widgetFormModel);
this._widgetDefinitionModel.on('change:title', function (model, title) {
this._widgetFormModel.set({title: title}, {silent: true}); // silent to avoid sending the form
}, this);
this._widgetDefinitionModel.bind('change:auto_style_definition', this._onAutoStyleChanged, this);
this.add_related_model(this._widgetDefinitionModel);
},
_initViews: function () {
var model = this._widgetFormModel;
var fields = model.getFields();
this._widgetFormView = new Backbone.Form({
template: template,
templateData: {
dataFields: fields.data,
styleFields: fields.style
},
model: model
});
this._widgetFormView.bind('change', function () {
this.commit();
});
this.$el.append(this._widgetFormView.render().$el);
return this;
},
validateForm: function () {
return this._widgetFormView.validate();
},
_removeForm: function () {
// Backbone.Form removes the view with the following method
this._widgetFormView && this._widgetFormView.remove();
},
_onFormChange: function () {
if (this._widgetFormModel.canSave()) {
this._widgetFormModel.changeWidgetDefinitionModel(this._widgetDefinitionModel);
this._debounceSaveWidget();
}
},
_onAutoStyleChanged: function (widgetDefModel, changedAttrs) {
var previousAutoStyleDefinition = widgetDefModel.previous('auto_style_definition');
if (previousAutoStyleDefinition === '' && _.isEmpty(previousAutoStyleDefinition)) {
this._widgetFormModel.set({
auto_style_definition: widgetDefModel.get('auto_style_definition')
}, {
silent: true
});
if (!_.isEmpty(changedAttrs)) {
this.render();
}
}
},
_saveWidget: function () {
this._userActions.saveWidget(this._widgetDefinitionModel);
},
clean: function () {
this._removeForm();
CoreView.prototype.clean.call(this);
}
});
@@ -0,0 +1,27 @@
<div class="Editor-HeaderInfo">
<div class="Editor-HeaderNumeration CDB-Text is-semibold u-rSpace--m">2</div>
<div class="Editor-HeaderInfo-inner CDB-Text">
<div class="Editor-HeaderInfo-title u-bSpace--m">
<h2 class="CDB-Text CDB-HeaderInfo-titleText CDB-Size-large"><%- _t('editor.widgets.widgets-form.data.title-label') %></h2>
</div>
<p class="CDB-Text u-upperCase CDB-FontSize-small u-altTextColor u-bSpace--m"><%- _t('editor.widgets.widgets-form.data.description') %></p>
<div data-fields="<%- dataFields %>"></div>
</div>
</div>
<div class="CDB-HeaderInfo">
<div class="CDB-HeaderNumeration CDB-Text is-semibold u-rSpace--m">3</div>
<div class="Editor-HeaderInfo-inner CDB-Text">
<div class="Editor-HeaderInfo-title u-bSpace--m">
<h2 class="CDB-Text CDB-HeaderInfo-TitleText CDB-Size-large"><%- _t('editor.widgets.widgets-form.style.title-label') %></h2>
</div>
<p class="CDB-Text u-upperCase CDB-FontSize-small u-altTextColor u-bSpace--m"><%- _t('editor.widgets.widgets-form.style.define') %></p>
<div data-fields="<%- styleFields %>"></div>
</div>
</div>
@@ -0,0 +1,9 @@
<div class="Editor-HeaderInfo">
<div class="Editor-HeaderNumeration CDB-Text is-semibold u-rSpace--m">1</div>
<div class="Editor-HeaderInfo-inner CDB-Text js-selector">
<div class="Editor-HeaderInfo-title u-bSpace--m">
<h2 class="CDB-Text CDB-HeaderInfo-titleText CDB-Size-large"><%- _t('editor.widgets.widgets-form.type.title-label') %></h2>
</div>
<p class="CDB-Text u-upperCase CDB-FontSize-small u-altTextColor u-bSpace--m js-highlight"><%- _t('editor.widgets.widgets-form.type.description') %></p>
</div>
</div>
@@ -0,0 +1,125 @@
var CoreView = require('backbone/core-view');
var _ = require('underscore');
var CarouselFormView = require('builder/components/carousel-form-view');
var CarouselCollection = require('builder/components/custom-carousel/custom-carousel-collection');
var WidgetFormFactory = require('./widgets-form-factory');
var WidgetsFormFieldsView = require('./widgets-form-fields-view');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var loadingTemplate = require('builder/editor/layers/panel-loading-template.tpl');
var TIME_SERIES_TYPE = 'time-series';
var REQUIRED_OPTS = [
'userActions',
'widgetDefinitionModel',
'modals',
'querySchemaModel',
'configModel',
'userModel'
];
module.exports = CoreView.extend({
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
this._initBinds();
this._shouldFetchQuery();
},
render: function () {
this.clearSubViews();
this.$el.empty();
if (!this._querySchemaModel.isFetched()) {
this.$el.html(loadingTemplate());
} else {
this._renderCarousel();
this._renderForm();
}
return this;
},
_initBinds: function () {
this.listenTo(this._widgetDefinitionModel, 'change:type', this._renderFormAndValidate);
this.listenTo(this._querySchemaModel, 'change:status', this.render);
this.listenTo(this._querySchemaModel, 'change:query', this._shouldFetchQuery);
},
_shouldFetchQuery: function () {
if (this._querySchemaModel.shouldFetch()) {
this._querySchemaModel.fetch();
}
},
_renderCarousel: function () {
var filteredDataTypes = this._getFilteredDataTypes();
var carouselCollection = new CarouselCollection(
_.map(filteredDataTypes, function (type) {
return {
selected: this._widgetDefinitionModel.get('type') === type.value,
val: type.value,
label: type.label,
template: function () {
return (type.iconTemplate && type.iconTemplate({ makeItBig: true })) || type.value;
}
};
}, this)
);
carouselCollection.bind('change:selected', function (mdl) {
if (mdl.get('selected')) {
this._widgetDefinitionModel.changeType(mdl.getValue());
}
}, this);
var view = new CarouselFormView({
collection: carouselCollection,
template: require('./widgets-form-types.tpl')
});
this.addView(view);
this.$el.append(view.render().el);
},
_getFilteredDataTypes: function () {
var containsTimeSeries = false;
var modelCollection = this._widgetDefinitionModel.collection;
if (modelCollection) {
containsTimeSeries = modelCollection.any(function (model) {
return model.get('type') === TIME_SERIES_TYPE;
});
}
var filteredDataTypes = _.filter(WidgetFormFactory.getDataTypes(this._querySchemaModel), function (type) {
// Do not allow to change the widget to time-series if there is already a time-series widget
return (!containsTimeSeries ||
type.value !== TIME_SERIES_TYPE ||
this._widgetDefinitionModel.get('type') === TIME_SERIES_TYPE);
}, this);
return filteredDataTypes;
},
_renderFormAndValidate: function () {
this._renderForm();
if (this._formView.validateForm() === null) {
this._userActions.saveWidget(this._widgetDefinitionModel);
}
},
_renderForm: function () {
if (this._formView) {
this.removeView(this._formView);
this._formView.clean();
}
this._formView = new WidgetsFormFieldsView({
userActions: this._userActions,
widgetDefinitionModel: this._widgetDefinitionModel,
querySchemaModel: this._querySchemaModel,
modals: this._modals,
userModel: this._userModel,
configModel: this._configModel
});
this.addView(this._formView);
this.$el.append(this._formView.render().el);
}
});