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,14 @@
<svg width="42px" height="18px" viewBox="7 7 42 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Group" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(7.000000, 7.000000)">
<rect id="Rectangle-680" fill="#DDDDDD" x="0" y="0" width="11" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="0" y="4" width="9" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="0" y="8" width="16" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="0" y="12" width="13" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="0" y="16" width="16" height="2"></rect>
<ellipse id="Oval-1585" fill-opacity="0.2" fill="#9DE0AD" cx="33" cy="9" rx="9" ry="9"></ellipse>
<ellipse id="Oval-1585" fill-opacity="0.4" fill="#9DE0AD" cx="33" cy="11" rx="7" ry="7"></ellipse>
<ellipse id="Oval-1585" fill-opacity="0.5" fill="#9DE0AD" cx="33" cy="13" rx="5" ry="5"></ellipse>
<ellipse id="Oval-1585" fill-opacity="0.8" fill="#9DE0AD" cx="33" cy="15" rx="3" ry="3"></ellipse>
<ellipse id="Oval-1585" fill="#9DE0AD" cx="33" cy="17" rx="1" ry="1"></ellipse>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,21 @@
<svg width="56px" height="32px" viewBox="529 429 56 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<rect id="path-1" x="0" y="0" width="56" height="32" rx="2"></rect>
<mask id="mask-2" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox" x="0" y="0" width="56" height="32" fill="white">
<use xlink:href="#path-1"></use>
</mask>
</defs>
<g id="category" transform="translate(529.000000, 429.000000)">
<use id="Rectangle-2" stroke="#EEEEEE" mask="url(#mask-2)" stroke-width="2" fill="#FFFFFF" xlink:href="#path-1"></use>
<rect id="Rectangle-679" fill="#DDDDDD" x="7" y="15" width="23" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="7" y="19" width="13" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="7" y="23" width="10" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="7" y="11" width="13" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="7" y="7" width="19" height="2"></rect>
<rect id="Rectangle-680" fill="#9CE0AC" x="45" y="7" width="3" height="2"></rect>
<rect id="Rectangle-680" fill="#F4F1DE" x="45" y="11" width="3" height="2"></rect>
<rect id="Rectangle-680" fill="#E17C60" x="45" y="15" width="3" height="2"></rect>
<rect id="Rectangle-680" fill="#3D3F5B" x="45" y="19" width="3" height="2"></rect>
<rect id="Rectangle-680" fill="#F2CD8F" x="45" y="23" width="3" height="2"></rect>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,21 @@
<svg width="56px" height="32px" viewBox="529 429 56 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<rect id="path-1" x="0" y="0" width="56" height="32" rx="2"></rect>
<mask id="mask-2" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox" x="0" y="0" width="56" height="32" fill="white">
<use xlink:href="#path-1"></use>
</mask>
</defs>
<g id="category" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(529.000000, 429.000000)">
<use id="Rectangle-2" stroke="#EEEEEE" mask="url(#mask-2)" stroke-width="2" fill="#FFFFFF" xlink:href="#path-1"></use>
<rect id="Rectangle-679" fill="#DDDDDD" x="14" y="15" width="23" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="14" y="19" width="13" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="14" y="23" width="10" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="14" y="11" width="13" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="14" y="7" width="19" height="2"></rect>
<rect id="Rectangle-680" fill="#9CE0AC" x="7" y="7" width="3" height="2"></rect>
<rect id="Rectangle-680" fill="#F4F1DE" x="7" y="11" width="3" height="2"></rect>
<rect id="Rectangle-680" fill="#E17C60" x="7" y="15" width="3" height="2"></rect>
<rect id="Rectangle-680" fill="#3D3F5B" x="7" y="19" width="3" height="2"></rect>
<rect id="Rectangle-680" fill="#F2CD8F" x="7" y="23" width="3" height="2"></rect>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,18 @@
<svg width="54px" height="24px" viewBox="519 458 54 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient x1="90.736547%" y1="49.7500002%" x2="9.63471511%" y2="49.7500002%" id="linearGradient-1">
<stop stop-color="#C11F22" offset="0%"></stop>
<stop stop-color="#F53F15" offset="23.9588524%"></stop>
<stop stop-color="#FF9030" offset="49.5142003%"></stop>
<stop stop-color="#FFCF52" offset="75.4982561%"></stop>
<stop stop-color="#FFFEAE" offset="100%"></stop>
</linearGradient>
</defs>
<g id="color" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(519.000000, 458.000000)">
<rect id="bg" fill="#FFFFFF" x="0" y="0" width="54" height="23" rx="2"></rect>
<path d="M1,20.9991358 C1,21.5484057 1.45096651,22 2.00209026,22 L51.9979097,22 C52.5538814,22 53,21.5535154 53,20.9991358 L53,2.00086422 C53,1.45159429 52.5490335,1 51.9979097,1 L2.00209026,1 C1.44611861,1 1,1.44648455 1,2.00086422 L1,20.9991358 Z M2.00209026,0 L51.9979097,0 C53.1036337,0 54,0.901627257 54,2.00086422 L54,20.9991358 C54,22.1041826 53.1077828,23 51.9979097,23 L2.00209026,23 C0.896366344,23 0,22.0983727 0,20.9991358 L0,2.00086422 C0,0.895817426 0.892217249,0 2.00209026,0 Z" id="Rectangle-2087-Copy" fill="#EEEEEE"></path>
<rect id="Rectangle-680" fill="url(#linearGradient-1)" x="6" y="12" width="42" height="5"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="6" y="6" width="6" height="2"></rect>
<rect id="Rectangle-680" fill="#DDDDDD" x="42" y="6" width="6" height="2"></rect>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1 @@
<p class="CDB-Text CDB-Size-small u-upperCase u-altTextColor">None</p>
@@ -0,0 +1,5 @@
<ul class="CodeMirror-error">
<li class="CodeMirror-errorMessage u-lSpace--xl u-rSpace--xl">
<%- _t('components.codemirror.syntax-error') %>. <%- _t('components.codemirror.line') %> <%- line %>: <span><%- message %></span>
</li>
</ul>
@@ -0,0 +1,89 @@
var LegendTypes = require('builder/editor/layers/layer-content-views/legend/legend-types');
var styleHelper = require('builder/helpers/style');
module.exports = [
{
value: LegendTypes.NONE,
tooltipTranslationKey: 'editor.legend.tooltips.style.none',
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/none.tpl'),
label: _t('editor.legend.types.none')
}, {
value: LegendTypes.CATEGORY,
tooltipTranslationKey: 'editor.legend.tooltips.style.category',
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/category.tpl'),
label: _t('editor.legend.types.category'),
isStyleCompatible: function (styleModel) {
var color = styleHelper.getColor(styleModel);
if (color == null || styleModel.isAnimation()) return false;
var usesCategory = (color && color.quantification === 'category');
var hasStringAttribute = (color && color.attribute &&
color.attribute_type && color.attribute_type === 'string');
var hasBooleanAttribute = (color && color.attribute &&
color.attribute_type && color.attribute_type === 'boolean');
return (usesCategory || hasStringAttribute || hasBooleanAttribute);
}
}, {
value: LegendTypes.TORQUE,
tooltipTranslationKey: 'editor.legend.tooltips.style.torque',
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/category.tpl'),
label: _t('editor.legend.types.category'),
isStyleCompatible: function (styleModel) {
var color = styleHelper.getColor(styleModel);
if (color == null || !styleModel.isAnimation()) return false;
var usesCategory = (color && color.quantification === 'category');
var hasStringAttribute = (color && color.attribute &&
color.attribute_type && color.attribute_type === 'string');
return (usesCategory || hasStringAttribute);
}
}, {
value: LegendTypes.CHOROPLETH,
tooltipTranslationKey: 'editor.legend.tooltips.style.choropleth',
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/gradient.tpl'),
label: _t('editor.legend.types.gradient'),
isStyleCompatible: function (styleModel) {
var color = styleHelper.getColor(styleModel);
if (color == null) return false;
if (styleModel.isAnimation() || styleModel.isHeatmap()) return false;
var usesCategory = (color && color.quantification === 'category');
if (usesCategory) return false;
var attributeTypeIsBoolean = (color.attribute_type && color.attribute_type === 'boolean');
if (attributeTypeIsBoolean) return false;
var hasAttribute = color && color.attribute;
var attributeTypeIsUndef = (color.attribute_type === undefined);
var attributeTypeIsNotString = (color.attribute_type && color.attribute_type !== 'string');
return hasAttribute && (attributeTypeIsUndef || attributeTypeIsNotString);
}
}, {
value: LegendTypes.CUSTOM_CHOROPLETH,
tooltipTranslationKey: 'editor.legend.tooltips.style.custom_choropleth',
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/gradient.tpl'),
label: _t('editor.legend.types.gradient'),
isStyleCompatible: function (styleModel) {
var color = styleHelper.getColor(styleModel);
if (color == null || !styleModel.isHeatmap()) return false;
var hasAttribute = color && color.attribute;
var attributeTypeIsUndef = (color.attribute_type === undefined);
var attributeTypeIsNotString = (color.attribute_type && color.attribute_type !== 'string');
return hasAttribute && (attributeTypeIsUndef || attributeTypeIsNotString);
}
}, {
value: LegendTypes.CUSTOM,
tooltipTranslationKey: 'editor.legend.tooltips.style.custom',
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/custom.tpl'),
label: _t('editor.legend.types.custom')
}
];
@@ -0,0 +1,9 @@
var LegendTypes = require('./legend-color-types');
var LegendTypeBaseView = require('builder/editor/layers/layer-content-views/legend/legend-base-type-view');
module.exports = LegendTypeBaseView.extend({
initialize: function (opts) {
this.legendTypes = LegendTypes;
LegendTypeBaseView.prototype.initialize.call(this, opts);
}
});
@@ -0,0 +1,13 @@
<ul>
<% for(var i in items) { %>
<li class="Legend-categoryListItem u-flex u-alignCenter">
<% if (items[i].icon) { %>
<span class="Legend-categoryIcon js-image-container" data-icon="<%= items[i].icon %>" <% if (items[i].color) { %>data-color="<%= items[i].color %>"<% } %>></span>
<% } else if (items[i].color) { %>
<span class="Legend-categoryCircle" style="opacity:1; background: <%= items[i].color %>;"></span>
<% } %>
<p class="Legend-categoryTitle CDB-Text CDB-Size-small u-upperCase u-ellipsis" title="<%= items[i].title %>"><%= items[i].title %></p>
</li>
<% } %>
</ul>
@@ -0,0 +1,3 @@
<h2 class="CDB-Text CDB-Size-huge is-light u-secondaryTextColor">
<%- _t('editor.legend.message') %>
</h2>
@@ -0,0 +1,46 @@
var Backbone = require('backbone');
var _ = require('underscore');
/*
Base model form legend.
*/
module.exports = Backbone.Model.extend({
defaults: {
type: 'none',
title: ''
},
initialize: function (attrs, opts) {
if (!opts.legendDefinitionModel) throw new Error('legendDefinitionModel is required');
this.legendDefinitionModel = opts.legendDefinitionModel;
this.schema = this._generateSchema();
},
_generateSchema: function () {
return {
title: {
type: 'EnablerEditor',
title: '',
label: _t('editor.legend.legend-form.title.label'),
defaultValue: this._titlePlaceholder,
editor: {
type: 'Text',
editorAttrs: {
placeholder: this._titlePlaceholder,
help: _t('editor.legend.legend-form.title.help')
}
}
}
};
},
toJSON: function () {
return _.extend(
this.attributes,
{
type: this.get('type')
}
);
}
});
@@ -0,0 +1,79 @@
var _ = require('underscore');
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
var LegendBaseDefModel = require('./legend-base-definition-form-model');
var LegendColorHelper = require('./legend-color-helper');
module.exports = LegendBaseDefModel.extend({
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
{
type: 'bubble',
fillColor: null
}
),
initialize: function (attrs, opts) {
this._titlePlaceholder = _t('editor.legend.legend-form.by-size');
LegendBaseDefModel.prototype.initialize.call(this, attrs, opts);
this.on('change:fill', function () {
this.set('fillColor', this.get('fill').color.fixed);
}, this);
this._initialColor();
},
toJSON: function () {
return _.extend(
{},
_.omit(this.attributes, 'fill')
);
},
_initialColor: function () {
var color = this.legendDefinitionModel.get('fillColor');
var fill = LegendColorHelper.getBubbles(color);
this.set({fill: fill});
},
_generateSchema: function () {
var schema = LegendBaseDefModel.prototype._generateSchema.call(this);
return _.extend(
schema,
{
fill: {
type: 'Fill',
title: _t('editor.legend.legend-form.fill'),
options: [],
dialogMode: DialogConstants.Mode.FLOAT,
editorAttrs: {
color: {
hidePanes: ['value']
}
}
},
topLabel: {
type: 'EnablerEditor',
title: '',
label: _t('editor.legend.legend-form.top-label'),
editor: {
type: 'Text',
editorAttrs: {
placeholder: _t('editor.legend.legend-form.custom-label-placeholder')
}
}
},
bottomLabel: {
type: 'EnablerEditor',
title: '',
label: _t('editor.legend.legend-form.bottom-label'),
editor: {
type: 'Text',
editorAttrs: {
placeholder: _t('editor.legend.legend-form.custom-label-placeholder')
}
}
}
}
);
}
});
@@ -0,0 +1,15 @@
var _ = require('underscore');
var LegendBaseDefModel = require('./legend-base-definition-form-model');
module.exports = LegendBaseDefModel.extend({
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
{
type: 'category'
}
),
initialize: function (attrs, opts) {
this._titlePlaceholder = _t('editor.legend.legend-form.by-color');
LegendBaseDefModel.prototype.initialize.call(this, attrs, opts);
}
});
@@ -0,0 +1,66 @@
var _ = require('underscore');
var LegendBaseDefModel = require('./legend-base-definition-form-model');
module.exports = LegendBaseDefModel.extend({
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
{
type: 'choropleth',
prefix: '',
suffix: '',
leftLabel: '',
rightLabel: ''
}
),
initialize: function (attrs, opts) {
this._titlePlaceholder = _t('editor.legend.legend-form.by-color');
LegendBaseDefModel.prototype.initialize.call(this, attrs, opts);
},
_generateSchema: function () {
var schema = LegendBaseDefModel.prototype._generateSchema.call(this);
return _.extend(
schema,
{
leftLabel: {
type: 'EnablerEditor',
title: '',
label: _t('editor.legend.legend-form.left-label'),
editor: {
type: 'Text',
editorAttrs: {
placeholder: _t('editor.legend.legend-form.custom-label-placeholder')
}
}
},
rightLabel: {
type: 'EnablerEditor',
title: '',
label: _t('editor.legend.legend-form.right-label'),
editor: {
type: 'Text',
editorAttrs: {
placeholder: _t('editor.legend.legend-form.custom-label-placeholder')
}
}
},
suffix: {
type: 'EnablerEditor',
title: '',
label: _t('editor.legend.legend-form.suffix'),
editor: {
type: 'Text'
}
},
prefix: {
type: 'EnablerEditor',
title: '',
label: _t('editor.legend.legend-form.prefix'),
editor: {
type: 'Text'
}
}
}
);
}
});
@@ -0,0 +1,53 @@
var _ = require('underscore');
function buildSwatch (color, name, icon) {
if (_.isString(color)) {
color = {
fixed: color,
opacity: 1,
image: icon
};
}
return {
fill: {
color: color
},
title: name
};
}
function _unquote (c) {
return c && c.replace && c.replace(/^"(.+(?="$))"$/, '$1') || c;
}
function simpleColor (color) {
return [buildSwatch(color, '', color.image || '')];
}
function collectionColor (color) {
var range = color.range.length;
return _.range(range).map(function (v, index) {
// if style attribute is number there is no domain (choropleth)
return buildSwatch(
color.range[index],
color.domain && _unquote(color.domain[index]) || '',
color.images && color.images[index]);
});
}
module.exports = {
buildSwatch: buildSwatch,
getCategories: function (color) {
if (color.fixed !== undefined) {
return simpleColor(color);
} else if (color.attribute) {
return collectionColor(color);
}
},
unquoteColor: _unquote,
getBubbles: function (color) {
return _.omit(_.first(this.getCategories(color)), 'title').fill;
}
};
@@ -0,0 +1,35 @@
var _ = require('underscore');
function rotateCollection (array) {
var first = _.first(array);
array = _.rest(array);
return array.concat([first]);
}
var COLORS = [
'#66B79E',
'#E65176',
'#528995',
'#FF710F',
'#305482',
'#CCD859',
'#565175',
'#FFB927',
'#3EBCAE',
'#E54C1F'
];
module.exports = {
getNextColor: function () {
COLORS = rotateCollection(COLORS);
return _.first(COLORS);
},
getColors: function () {
return COLORS;
},
setColors: function (collection) {
COLORS = collection;
}
};
@@ -0,0 +1,10 @@
var _ = require('underscore');
var LegendBaseDefModel = require('./legend-choropleth-definition-form-model');
module.exports = LegendBaseDefModel.extend({
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
{
type: 'custom_choropleth'
}
)
});
@@ -0,0 +1,78 @@
var _ = require('underscore');
var LegendBaseDefModel = require('./legend-base-definition-form-model');
var NestedCategory = require('./legend-nested-category-definition-form-model');
var templateItem = require('./legend-list-item.tpl');
var templateList = require('./legend-list.tpl');
var LegendColorHelper = require('./legend-color-helper');
module.exports = LegendBaseDefModel.extend({
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
{
type: 'custom',
items: []
}
),
initialize: function (attrs, opts) {
if (!opts.userModel) throw new Error('userModel is required');
if (!opts.configModel) throw new Error('configModel is required');
if (!opts.modals) throw new Error('configModel is required');
this._userModel = opts.userModel;
this._configModel = opts.configModel;
this._modals = opts.modals;
this._titlePlaceholder = _t('editor.legend.legend-form.by-color');
LegendBaseDefModel.prototype.initialize.call(this, attrs, opts);
this._initialItems();
},
_initialItems: function () {
var items;
var categories = this.legendDefinitionModel.get('items');
items = categories.map(function (v, index) {
return LegendColorHelper.buildSwatch(v.color, v.title, v.icon);
});
this.set({items: items});
},
_generateSchema: function () {
var schema = LegendBaseDefModel.prototype._generateSchema.call(this);
return _.extend(
schema,
{
items: {
type: 'SortableList',
itemType: 'CategoryModel',
model: NestedCategory,
title: '',
itemTemplate: templateItem,
listTemplate: templateList,
editorAttrs: {
className: 'u-flex',
userModel: this._userModel,
configModel: this._configModel,
modals: this._modals
}
}
}
);
},
toJSON: function () {
return _.extend(
{},
_.omit(this.attributes, 'items'),
{
items: this.get('items').map(function (item) {
return {
title: item.title,
color: item.fill.color.fixed,
image: item.fill.color.image
};
})
}
);
}
});
@@ -0,0 +1,16 @@
<div class="LegendItem js-sortable">
<div class="LegendItem-listFieldsOrder CDB-Shape js-editable">
<div class="CDB-Shape-rectsHandle is-small">
<div class="CDB-Shape-rectsHandleItem CDB-Shape-rectsHandleItem--grey is-first"></div>
<div class="CDB-Shape-rectsHandleItem CDB-Shape-rectsHandleItem--grey is-second"></div>
<div class="CDB-Shape-rectsHandleItem CDB-Shape-rectsHandleItem--grey is-third"></div>
</div>
</div>
<div data-editor class="u-grow">
</div>
<button class="LegendItem-deleteButton js-editable js-remove-help" type="button" data-action="remove">
<svg width="8px" height="8px" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<polygon fill="#1181FB" points="4 3.435128 0.564872 0 0 0.564872 3.435128 4 0 7.435128 0.564872 8 4 4.564872 7.435128 8 8 7.435128 4.564872 4 8 0.564872 7.435128 0"></polygon>
</svg>
</button>
</div>
@@ -0,0 +1,10 @@
<div class="u-grow LegendItems-container">
<div data-items class="u-bSpace--xl">
</div>
<div class="u-flex u-justifyEnd" style="width: 100%;"> <!-- We need a fucking u-full helper -->
<button class="CDB-Text CDB-Size-small u-actionTextColor u-upperCase" type="button" data-action="add">
<%- _t('editor.legend.legend-form.add') %>
</button>
</div>
</div>
@@ -0,0 +1,59 @@
var _ = require('underscore');
var Backbone = require('backbone');
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
var LegendColors = require('./legend-color-range');
var defaultFill = {
color: {
fixed: '#fabada',
opacity: 0.9
}
};
module.exports = Backbone.Model.extend({
schema: {
fill: {
type: 'Fill',
title: '',
options: [],
dialogMode: DialogConstants.Mode.FLOAT,
editorAttrs: {
color: {
hidePanes: ['value'],
imageEnabled: true,
help: _t('editor.legend.tooltips.item.fill')
},
className: 'LegendItem-inner'
}
},
title: {
type: 'Text',
title: '',
editorAttrs: {
className: 'LegendItem-inner',
placeholder: _t('editor.legend.legend-form.untitled'),
help: _t('editor.legend.tooltips.item.title')
}
}
},
initialize: function (attrs, opts) {
this._userModel = opts.userModel;
this._configModel = opts.configModel;
this._modals = opts.modals;
this._setOptions();
var fill = _.clone(defaultFill);
if (attrs.fill === undefined) {
fill.color.fixed = LegendColors.getNextColor();
this.set({fill: fill}, {silent: true});
}
},
_setOptions: function () {
this.schema.fill.editorAttrs.userModel = this._userModel;
this.schema.fill.editorAttrs.configModel = this._configModel;
this.schema.fill.editorAttrs.modals = this._modals;
}
});
@@ -0,0 +1,10 @@
var _ = require('underscore');
var LegendBaseDefModel = require('./legend-category-definition-form-model');
module.exports = LegendBaseDefModel.extend({
defaults: _.extend({}, LegendBaseDefModel.prototype.defaults,
{
type: 'torque'
}
)
});
@@ -0,0 +1,401 @@
var cdb = require('internal-carto.js');
var _ = require('underscore');
var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
var PanelWithOptionsView = require('builder/components/view-options/panel-with-options-view');
var LegendContentView = require('./legend-content-view');
var LegendEditorView = require('./legend-editor-view');
var ScrollView = require('builder/components/scroll/scroll-view');
var TabPaneView = require('builder/components/tab-pane/tab-pane-view');
var TabPaneCollection = require('builder/components/tab-pane/tab-pane-collection');
var Toggler = require('builder/components/toggler/toggler-view');
var ApplyButtonView = require('builder/components/apply-button/apply-button-view');
var Infobox = require('builder/components/infobox/infobox-factory');
var InfoboxCollection = require('builder/components/infobox/infobox-collection');
var LegendDefinitionModel = require('builder/data/legends/legend-base-definition-model');
var LegendFactory = require('./legend-factory');
var htmlTemplate = require('./color/legend-custom-template.tpl');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var MetricsTracker = require('builder/components/metrics/metrics-tracker');
var MetricsTypes = require('builder/components/metrics/metrics-types');
var REQUIRED_OPTS = [
'mapDefinitionModel',
'layerDefinitionModel',
'editorModel',
'layerContentModel',
'legendDefinitionsCollection',
'type',
'userActions',
'userModel',
'configModel',
'modals',
'overlayModel',
'infoboxModel'
];
var PLACEHOLDER = '[[Legend]]';
var HTML_TEMPLATE = _.template('<%= preSnippet %>\r\n<%- placeholder %>\r\n<%= postSnippet %>');
module.exports = CoreView.extend({
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
// this.legendTypes is defined in the subview
this._legendDefinitionModel = this._getUserLegend(this.legendTypes);
this._codemirrorModel = new Backbone.Model({
content: this._getEditorContent()
});
this._editorModel.set({
edition: this._legendDefinitionModel.hasCustomHtml(),
disabled: this._isToggleDisable() // if there is an sql error or none style is selected, set to true
});
this._overlayModel.set({
visible: this._isLayerHidden() || this._legendDefinitionModel.hasCustomHtml()
}, {
silent: true
});
this._togglerModel = new Backbone.Model({
labels: [_t('editor.legend.data-toggle.values'), _t('editor.legend.data-toggle.html')],
active: this._editorModel.isEditing(),
disabled: this._editorModel.isDisabled(),
isDisableable: true,
tooltip: _t('editor.legend.data-toggle.tooltip')
});
this._configPanes();
this._initBinds();
},
render: function () {
this.clearSubViews();
this.$el.empty();
this._initViews();
this._infoboxState();
this._toggleOverlay();
return this;
},
_initBinds: function () {
this.listenTo(this._layerContentModel, 'change:state', this._infoboxState);
this.listenTo(this._layerDefinitionModel, 'change:visible', this._infoboxState);
this.listenTo(this._mapDefinitionModel, 'change:legends', this._infoboxState);
this.listenTo(this._editorModel, 'change:edition', this._onChangeEdition);
this.listenTo(this._editorModel, 'change:disabled', this._onChangeDisabled);
this.listenTo(this._togglerModel, 'change:active', this._onTogglerChanged);
this.listenTo(this._overlayModel, 'change:visible', this._toggleOverlay);
},
_getEditorContent: function () {
var content;
var type = this._legendDefinitionModel.get('type');
if (type === 'custom') {
if (this._legendDefinitionModel.hasCustomHtml()) {
content = this._legendDefinitionModel.get('html');
} else {
content = '';
}
} else {
content = this._getReadOnlyContent();
}
return content;
},
_getReadOnlyContent: function () {
var content = HTML_TEMPLATE({
preSnippet: this._legendDefinitionModel.get('preHTMLSnippet') || _t('editor.legend.code-mirror.pre-html'),
placeholder: PLACEHOLDER,
postSnippet: this._legendDefinitionModel.get('postHTMLSnippet') || _t('editor.legend.code-mirror.post-html')
});
return content;
},
_getCustomContent: function () {
var items;
var result = this._legendDefinitionModel.get('html');
if (result === '') {
items = this._legendDefinitionModel.get('items');
result = htmlTemplate({ items: items });
}
return result;
},
_handleEditorContent: function (expertMode) {
var type = this._legendDefinitionModel.get('type');
if (expertMode) {
this._codemirrorModel.set({ content: type === 'custom' ? this._getCustomContent() : this._getReadOnlyContent() });
}
},
_getUserLegend: function (types) {
var self = this;
var values = _.map(types, function (type) { return type.value; });
var selected = this._legendDefinitionsCollection.find(function (legendDefModel) {
return values.indexOf(legendDefModel.get('type')) !== -1 && legendDefModel.layerDefinitionModel.id === self._layerDefinitionModel.id;
});
if (selected === undefined) {
selected = new LegendDefinitionModel(null, {
layerDefinitionModel: this._layerDefinitionModel,
configModel: this._legendDefinitionsCollection.configModel,
vizId: this._legendDefinitionsCollection.vizId
});
}
return selected;
},
_isToggleDisable: function () {
return this._isErrored() || this._legendDefinitionModel.get('type') === 'none' || this._areLegendsDisabled();
},
_isLayerHidden: function () {
return this._layerDefinitionModel.get('visible') === false;
},
_isErrored: function () {
return this._layerContentModel.isErrored();
},
_toggleOverlay: function () {
var isDisabled = this._overlayModel.get('visible');
this.$('.js-overlay').toggleClass('is-disabled', isDisabled);
},
_onChangeState: function () {
this._editorModel.set({ disabled: this._isErrored() });
},
_onChangeEdition: function () {
this._infoboxState();
var edition = this._editorModel.get('edition');
this._handleEditorContent(edition);
var index = edition ? 1 : 0;
this._collectionPane.at(index).set({ selected: true });
this._togglerModel.set({ active: edition });
},
_onChangeDisabled: function () {
var disabled = this._editorModel.get('disabled');
this._togglerModel.set({ disabled: disabled });
},
_onTogglerChanged: function () {
var checked = this._togglerModel.get('active');
this._editorModel.set({ edition: checked });
},
_initViews: function () {
var self = this;
var infoboxSstates = [
{
state: 'html-legend',
createContentView: function () {
return Infobox.createWithAction({
type: 'alert',
title: _t('editor.legend.messages.custom-legend.title'),
body: _t('editor.legend.messages.custom-legend.body'),
action: {
label: _t('editor.legend.messages.custom-legend.accept')
}
});
},
onAction: self._deleteCustomHtmlLegend.bind(self)
}, {
state: 'layer-hidden',
createContentView: function () {
return Infobox.createWithAction({
type: 'alert',
title: _t('editor.messages.layer-hidden.title'),
body: _t('editor.messages.layer-hidden.body'),
action: {
label: _t('editor.messages.layer-hidden.show')
}
});
},
onAction: self._showHiddenLayer.bind(self)
}, {
state: 'legends-disabled',
createContentView: function () {
return Infobox.createWithAction({
type: 'alert',
title: _t('editor.legend.messages.legends-disabled.title'),
body: _t('editor.legend.messages.legends-disabled.body'),
action: {
label: _t('editor.legend.messages.legends-disabled.show')
}
});
},
onAction: self._enableLegends.bind(self)
}
];
var infoboxCollection = new InfoboxCollection(infoboxSstates);
var panelWithOptionsView = new PanelWithOptionsView({
className: 'Editor-content',
editorModel: self._editorModel,
infoboxModel: self._infoboxModel,
infoboxCollection: infoboxCollection,
createContentView: function () {
return new TabPaneView({
collection: self._collectionPane
});
},
createControlView: function () {
return new Toggler({
model: self._togglerModel
});
},
createActionView: function () {
return new TabPaneView({
collection: self._collectionPane,
createContentKey: 'createActionView'
});
}
});
this.$el.append(panelWithOptionsView.render().el);
this.addView(panelWithOptionsView);
},
_showHiddenLayer: function () {
var savingOptions = {
shouldPreserveAutoStyle: true
};
this._layerDefinitionModel.toggleVisible();
this._userActions.saveLayer(this._layerDefinitionModel, savingOptions);
},
_deleteCustomHtmlLegend: function () {
var type = this._legendDefinitionModel.get('type');
this._legendDefinitionModel && this._legendDefinitionModel.set({
html: ''
});
LegendFactory.createLegend(this._layerDefinitionModel, type);
this._infoboxState();
},
_saveLegendHTML: function () {
var content = this._codemirrorModel.get('content');
var type = this._legendDefinitionModel.get('type');
var parts;
if (type === 'custom') {
this._legendDefinitionModel && this._legendDefinitionModel.set({
html: content
});
} else {
parts = content.split(PLACEHOLDER).map(function (part) {
return cdb.core.sanitize.html(part);
});
this._legendDefinitionModel && this._legendDefinitionModel.set({
preHTMLSnippet: parts[0],
postHTMLSnippet: parts[1]
});
}
MetricsTracker.track(MetricsTypes.USED_ADVANCED_MODE, {
mode_type: 'legend'
});
LegendFactory.createLegend(this._layerDefinitionModel, type);
},
_infoboxState: function () {
var edition = this._editorModel.get('edition');
if (!edition && this._areLegendsDisabled()) {
this._infoboxModel.set({ state: 'legends-disabled' });
this._overlayModel.set({ visible: true });
this._togglerModel.set({ disabled: true });
} else if (!edition && this._legendDefinitionModel.hasCustomHtml()) {
this._infoboxModel.set({ state: 'html-legend' });
this._overlayModel.set({ visible: true });
} else if (this._isLayerHidden()) {
this._infoboxModel.set({ state: 'layer-hidden' });
this._overlayModel.set({ visible: true });
this._togglerModel.set({ disabled: true });
} else {
this._infoboxModel.set({ state: '' });
this._overlayModel.set({ visible: false });
this._togglerModel.set({ disabled: false });
}
},
_areLegendsDisabled: function () {
return this._mapDefinitionModel.get('legends') === false;
},
_enableLegends: function () {
this._mapDefinitionModel.save({ legends: true });
},
// we need to update the reference to the model
_updateLegend: function (newLegendDefModel) {
this._legendDefinitionModel = newLegendDefModel;
},
_configPanes: function () {
var self = this;
var tabPaneTabs = [{
selected: !self._legendDefinitionModel.hasCustomHtml(),
createContentView: function () {
return new ScrollView({
createContentView: function () {
return new LegendContentView({
className: 'Editor-content',
editorModel: self._editorModel,
legendTypes: self.legendTypes,
layerDefinitionModel: self._layerDefinitionModel,
legendDefinitionModel: self._getUserLegend(self.legendTypes),
legendDefinitionsCollection: self._legendDefinitionsCollection,
updateLegend: self._updateLegend.bind(self),
type: self._type,
userModel: self._userModel,
configModel: self._configModel,
modals: self._modals
});
}
});
},
createActionView: function () {
return new CoreView();
}
}, {
selected: self._legendDefinitionModel.hasCustomHtml(),
createContentView: function () {
return new LegendEditorView({
isCustom: self._legendDefinitionModel.get('type') === 'custom',
codemirrorModel: self._codemirrorModel,
onApplyEvent: self._saveLegendHTML.bind(self)
});
},
createActionView: function () {
return new ApplyButtonView({
onApplyClick: self._saveLegendHTML.bind(self),
overlayModel: self._overlayModel
});
}
}];
this._collectionPane = new TabPaneCollection(tabPaneTabs);
}
});
@@ -0,0 +1,89 @@
var _ = require('underscore');
var LEGEND_TYPES_PER_ATTRIBUTE = {
color: ['category', 'choropleth', 'custom', 'custom_choropleth', 'torque'],
size: ['bubble']
};
function LegendBuffer (opts) {
this.queue = [];
this.running = false;
this._legendDefinitionsCollection = opts.legendDefinitionsCollection;
}
LegendBuffer.prototype.add = function (model, callback) {
this._cleanQueue(model.get('layer_id'), model.get('type'));
this.queue.push(model);
if (!this.running) {
this.running = true;
this._run(callback);
}
};
LegendBuffer.prototype._run = function (callback) {
if (this.running === false || this.queue.length === 0) {
this.running = false;
return;
}
var model = this.queue.shift();
this._removePrevious(model.layerDefinitionModel.get('id'), model.get('type'), function () {
model.save(null, {
success: function (model) {
this._legendDefinitionsCollection.add(model);
this._run();
}.bind(this),
complete: function () {
callback && callback();
}
});
}.bind(this));
};
LegendBuffer.prototype._removePrevious = function (layer_id, type, callback) {
var types = this._findSameType(type);
var removeLegends = this._legendDefinitionsCollection.filter(function (legend) {
return legend.get('layer_id') === layer_id && _.includes(types, legend.get('type'));
});
var legendsLeft = removeLegends.length;
if (this._legendDefinitionsCollection.size() === 0 || removeLegends.length === 0) {
callback && callback();
return;
}
_.each(removeLegends, function (legend) {
legend.destroy({
complete: function () {
// In case there's more than one legend to be removed (shouldn't be possible), we should wait for all to be removed
legendsLeft = legendsLeft - 1;
if (legendsLeft === 0) {
callback && callback();
}
}
});
});
};
LegendBuffer.prototype._cleanQueue = function (layer_id, type) {
var types = this._findSameType(type);
this.queue = _.reject(this.queue, function (legend) {
return legend.get('layer_id') === layer_id && _.includes(types, legend.get('type'));
});
};
LegendBuffer.prototype._findSameType = function (type) {
return _.find(LEGEND_TYPES_PER_ATTRIBUTE, function (collection, name) {
return _.include(collection, type);
});
};
LegendBuffer.prototype.findLegend = function (layer_id, type) {
return _.findWhere(this.queue, { layer_id: layer_id, type: type });
};
module.exports = LegendBuffer;
@@ -0,0 +1,3 @@
<h2 class="CDB-Text CDB-Size-huge is-light u-secondaryTextColor">
<%= body %>
</h2>
@@ -0,0 +1,217 @@
var CoreView = require('backbone/core-view');
var _ = require('underscore');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var styleHelper = require('builder/helpers/style');
var CarouselFormView = require('builder/components/carousel-form-view');
var CarouselCollection = require('builder/components/custom-carousel/custom-carousel-collection');
var FormView = require('./legend-properties-form');
var CustomFormModel = require('./form/legend-custom-definition-form-model');
var CategoryFormModel = require('./form/legend-category-definition-form-model');
var BubbleFormModel = require('./form/legend-bubble-definition-form-model');
var ChoroplethFormModel = require('./form/legend-choropleth-definition-form-model');
var CustomChoroplethFormModel = require('./form/legend-custom-choropleth-definition-form-model');
var TorqueFormModel = require('./form/legend-torque-definition-form-model');
var template = require('./legend-content.tpl');
var LegendFactory = require('./legend-factory');
var DEBOUNCE_TIME = 350;
var REQUIRED_OPTS = [
'editorModel',
'legendTypes',
'updateLegend',
'layerDefinitionModel',
'legendDefinitionModel',
'legendDefinitionsCollection',
'type',
'userModel',
'configModel',
'modals'
];
var LEGEND_MODEL_TYPE = {
bubble: BubbleFormModel,
custom: CustomFormModel,
category: CategoryFormModel,
choropleth: ChoroplethFormModel,
custom_choropleth: CustomChoroplethFormModel,
torque: TorqueFormModel
};
module.exports = CoreView.extend({
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
var type = this._legendDefinitionModel.get('type');
this._onDebouncedChange = _.debounce(this._updateChanges.bind(this), DEBOUNCE_TIME);
this._lastType = type || 'none';
this._createFormModel(type);
var styleModel = this._layerDefinitionModel.styleModel;
this._carouselCollection = new CarouselCollection(
_.chain(this._legendTypes).filter(function (legend) {
return legend.isStyleCompatible ? legend.isStyleCompatible(styleModel) : true;
}, this).map(function (legend) {
return {
selected: type === legend.value,
val: legend.value,
label: legend.label,
template: function () {
return (legend.legendIcon && legend.legendIcon()) || legend.value;
},
tooltip: _t(legend.tooltipTranslationKey)
};
}, this).value()
);
this._initBinds();
},
render: function () {
this.clearSubViews();
this.$el.empty();
this.$el.html(template());
this._initViews();
return this;
},
_initBinds: function () {
this.listenTo(this._carouselCollection, 'change:selected', this._onCarouselChange);
},
_initViews: function () {
var type = this._legendDefinitionModel.get('type');
this._renderCarousel();
this._renderForm(type);
this._updateToggle(type);
},
_createFormModel: function (type) {
var Klass;
var attrs;
if (this._formModel) {
this._unBindFormModel(this._formModel);
delete this._formModel;
}
if (type && type !== 'none') {
Klass = LEGEND_MODEL_TYPE[type];
attrs = this._pickAttrs(this._legendDefinitionModel);
this._formModel = new Klass(attrs, {
legendDefinitionModel: this._legendDefinitionModel,
userModel: this._userModel,
configModel: this._configModel,
modals: this._modals
});
this._bindFormModel(this._formModel);
}
},
_pickAttrs: function (legendDefinitionModel) {
var attrs = _.pick(legendDefinitionModel.attributes, 'title', 'prefix', 'suffix', 'leftLabel', 'rightLabel', 'topLabel', 'bottomLabel', 'items');
return attrs;
},
_onCarouselChange: function (model) {
var type = model.getValue();
if (model.get('selected') === true) {
this._updateLegendModel(type);
this._createFormModel(type);
this._renderForm(type);
this._updateToggle(type);
}
},
_updateLegendModel: function (type) {
var attrs;
if (type && type !== 'none') {
attrs = this._getDefaultAttributes(this._layerDefinitionModel, type);
LegendFactory.enableLegend(this._type);
this._legendDefinitionModel = LegendFactory.createLegend(this._layerDefinitionModel, type, attrs);
this._updateLegend(this._legendDefinitionModel);
} else {
LegendFactory.disableLegend(type);
LegendFactory.removeLegend(this._layerDefinitionModel, this._lastType);
this._updateLegend(null);
delete this._legendDefinitionModel;
}
this._lastType = type;
},
_getDefaultAttributes: function (layerDefModel, type) {
if (type === 'torque' || type === 'choropleth') {
return {
title: styleHelper.getColorAttribute(layerDefModel.styleModel)
};
}
},
_renderForm: function (type) {
this._removeForm();
if (type && type !== 'none') {
this._addForm();
}
},
_addForm: function () {
this._formView = new FormView({
formModel: this._formModel
});
this.addView(this._formView);
this.$('.js-form').html(this._formView.render().el);
},
_removeForm: function () {
if (this._formView) {
this.removeView(this._formView);
this._formView.clean();
}
},
_updateToggle: function (type) {
var isDisabled = type === 'none';
this._editorModel.set({disabled: isDisabled});
},
_renderCarousel: function () {
var view = new CarouselFormView({
collection: this._carouselCollection,
template: require('./legend-form-types.tpl')
});
this.addView(view);
this.$('.js-carousel').html(view.render().el);
},
_bindFormModel: function (model) {
if (model) {
model.on('change', this._onDebouncedChange, this);
this.add_related_model(model);
}
},
_unBindFormModel: function (model) {
model && model.off('change', this._onDebouncedChange, this);
},
_updateChanges: function () {
if (this._legendDefinitionModel) {
this._legendDefinitionModel.setAttributes(this._formModel.toJSON());
LegendFactory.createLegend(this._layerDefinitionModel, this._legendDefinitionModel.get('type'));
}
}
});
@@ -0,0 +1,2 @@
<div class="js-carousel"></div>
<div class="js-form"></div>
@@ -0,0 +1,56 @@
var CoreView = require('backbone/core-view');
var CodeMirrorView = require('builder/components/code-mirror/code-mirror-view');
var ErrorTemplate = require('./code-mirror-error.tpl');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var REQUIRED_OPTS = [
'codemirrorModel',
'onApplyEvent',
'isCustom'
];
var PLACEHOLDER = '[[Legend]]';
module.exports = CoreView.extend({
module: 'editor:layers:layer-content-views:legend:legend-editor-view',
className: 'Editor-content',
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
},
render: function () {
this.clearSubViews();
this.$el.empty();
this._initViews();
return this;
},
_initViews: function () {
this.codeMirrorView = new CodeMirrorView({
model: this._codemirrorModel,
tips: [
_t('editor.legend.code-mirror.save')
],
errorTemplate: ErrorTemplate
});
this.codeMirrorView.bind('codeSaved', this._triggerCodeSaved, this);
this.addView(this.codeMirrorView);
this.$el.append(this.codeMirrorView.render().el);
if (!this._isCustom) {
this._markReadOnly();
}
},
_markReadOnly: function () {
var cursor = this.codeMirrorView.search(PLACEHOLDER);
this.codeMirrorView.markReadOnly(cursor.from, cursor.to);
},
_triggerCodeSaved: function (code, view) {
this.options.onApplyEvent && this.options.onApplyEvent();
}
});
@@ -0,0 +1,126 @@
var _ = require('underscore');
var CategoryModel = require('builder/data/legends/legend-category-definition-model');
var BubbleModel = require('builder/data/legends/legend-bubble-definition-model');
var ChoroplethModel = require('builder/data/legends/legend-choropleth-definition-model');
var CustomChoroplethModel = require('builder/data/legends/legend-custom-choropleth-definition-model');
var CustomModel = require('builder/data/legends/legend-custom-definition-model');
var TorqueModel = require('builder/data/legends/legend-torque-definition-model');
var Validations = require('./legend-validations');
var Buffer = require('./legend-buffer');
var LEGEND_MODEL_TYPE = {
'bubble': BubbleModel,
'category': CategoryModel,
'choropleth': ChoroplethModel,
'custom_choropleth': CustomChoroplethModel,
'custom': CustomModel,
'torque': TorqueModel
};
var manager = (function () {
return {
init: function (legendDefinitionsCollection) {
if (!legendDefinitionsCollection) {
throw new Error('legendDefinitionsCollection is required');
}
this.legendDefinitionsCollection = legendDefinitionsCollection;
this.legendBuffer = new Buffer({
legendDefinitionsCollection: this.legendDefinitionsCollection
});
},
getLegendsCollection: function () {
return this.legendDefinitionsCollection;
},
save: function (model, callback) {
model.save(null, {complete: function (model) {
callback && callback();
}});
},
remove: function (model, callback) {
var self = this;
model.destroy({
success: function (model) {
self.legendDefinitionsCollection.remove(model);
},
complete: function () {
callback && callback();
}
});
},
createLegend: function (layerDefModel, type, attrs, callback) {
var model = this.legendDefinitionsCollection.findByLayerDefModelAndType(layerDefModel, type);
var Klass;
var validation = Validations[type];
var isValid = validation(layerDefModel.styleModel);
attrs = attrs || {};
if (!model) {
Klass = LEGEND_MODEL_TYPE[type];
model = new Klass(attrs, {
layerDefinitionModel: layerDefModel,
configModel: this.legendDefinitionsCollection.configModel,
vizId: this.legendDefinitionsCollection.vizId,
parse: true
});
if (isValid) {
this.legendBuffer.add(model, callback);
}
} else {
if (!isValid) {
this.remove(model, callback);
} else {
model.set(attrs);
this.save(model, callback);
}
}
return model;
},
removeLegend: function (layerDefModel, type, cb) {
var legend = this.legendDefinitionsCollection.findByLayerDefModelAndType(layerDefModel, type);
if (legend) {
this.remove(legend, cb);
} else {
cb && cb();
}
return legend;
},
find: function (layerDefModel, type) {
return this.legendDefinitionsCollection.findByLayerDefModelAndType(layerDefModel, type);
},
removeAllLegend: function (layerDefModel) {
var legends = this.legendDefinitionsCollection.findByLayerDefModel(layerDefModel);
_.each(legends, function (legend) {
legend.get('type') !== 'custom' && this.remove(legend);
}, this);
},
hasMigratedLegend: function (layerDefModel) {
var legend = this.legendDefinitionsCollection.findByLayerDefModelAndType(layerDefModel, 'html');
return !!legend;
},
disableLegend: function (type) {
this[type] = false;
},
enableLegend: function (type) {
this[type] = true;
},
// By default, it's undefined so we are removing this condition from the equation
isEnabledType: function (type) {
return this[type] === undefined ? true : !!this[type];
}
};
})();
module.exports = manager;
@@ -0,0 +1,11 @@
<div class="Editor-HeaderInfo">
<div class="Editor-HeaderNumeration CDB-Text is-semibold u-rSpace--m">1</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.legend.legend-form.type.title') %></h2>
</div>
<div class="js-selector u-bSpace--xl">
<p class="CDB-Text u-upperCase CDB-FontSize-small u-altTextColor u-bSpace--m js-highlight"><%- name %></p>
</div>
</div>
</div>
@@ -0,0 +1,49 @@
var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
var template = require('./legend-properties-form.tpl');
require('builder/components/form-components/index');
module.exports = CoreView.extend({
initialize: function (opts) {
if (!opts.formModel) throw new Error('formModel is required');
this._formModel = opts.formModel;
},
render: function () {
this.clearSubViews();
this._removeFormView();
this.$el.html(template());
this._initViews();
return this;
},
_initViews: function () {
this._formView = new Backbone.Form({
model: this._formModel
});
this.listenTo(this._formView, 'change', this._updateChanges, this);
this.$('.js-propertiesForm').append(this._formView.render().el);
this.$('form').on('submit', function (event) {
event.preventDefault();
});
},
_updateChanges: function () {
this._formView.commit();
},
_removeFormView: function () {
this._formView && this._formView.remove();
},
clean: function () {
this.$('form').off('submit');
this._removeFormView();
CoreView.prototype.clean.call(this);
}
});
@@ -0,0 +1,10 @@
<div class="Editor-HeaderInfo">
<div class="Editor-HeaderNumeration CDB-Text is-semibold u-rSpace--m">2</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.legend.legend-form.properties.title') %></h2>
</div>
<p class="CDB-Text u-upperCase CDB-FontSize-small u-altTextColor u-bSpace--m"><%- _t('editor.legend.legend-form.properties.subtitle') %></p>
<div class="js-propertiesForm"></div>
</div>
</div>
@@ -0,0 +1,11 @@
var LEGEND_TYPES = {
NONE: 'none',
BUBBLE: 'bubble',
CATEGORY: 'category',
CHOROPLETH: 'choropleth',
TORQUE: 'torque',
CUSTOM: 'custom',
CUSTOM_CHOROPLETH: 'custom_choropleth'
};
module.exports = LEGEND_TYPES;
@@ -0,0 +1,51 @@
var _ = require('underscore');
var noOp = function () {
return true;
};
var getStyleAttrs = function (styleModel) {
var fill = styleModel.get('fill');
var stroke = styleModel.get('stroke');
if (!fill && !stroke || _.isEmpty(fill) && _.isEmpty(stroke)) return false;
return {
fill: fill,
stroke: stroke
};
};
var validateColorRange = function (styleModel) {
var attributes = getStyleAttrs(styleModel);
if (!attributes) return false;
var color = attributes.fill && attributes.fill.color || attributes.stroke && attributes.stroke.color;
return color.range && color.range.length > 0;
};
var validateSizeRange = function (styleModel) {
var attributes = getStyleAttrs(styleModel);
if (!attributes) return false;
var size = attributes.fill && attributes.fill.size || attributes.stroke && attributes.stroke.size;
return size.range && size.range.length > 0;
};
var validateRangeAndDomain = function (styleModel) {
var attributes = getStyleAttrs(styleModel);
if (!attributes) return false;
var color = attributes.fill && attributes.fill.color || attributes.stroke && attributes.stroke.color;
return color.range && color.range.length > 0 && color.domain && color.domain.length > 0 && color.range && color.range.length > 0;
};
var validations = {
bubble: validateSizeRange,
category: validateRangeAndDomain,
torque: validateRangeAndDomain,
choropleth: validateColorRange,
custom_choropleth: validateColorRange,
custom: noOp
};
module.exports = validations;
@@ -0,0 +1,232 @@
var Backbone = require('backbone');
var _ = require('underscore');
var CoreView = require('backbone/core-view');
var LegendColorView = require('./color/legend-color-view');
var LegendSizeView = require('./size/legend-size-view');
var LegendSizeTypes = require('./size/legend-size-types');
var createTextLabelsTabPane = require('builder/components/tab-pane/create-text-labels-tab-pane');
var TabPaneTemplate = require('builder/editor/tab-pane-submenu.tpl');
var sqlErrorTemplate = require('./legend-content-sql-error.tpl');
var actionErrorTemplate = require('builder/editor/layers/sql-error-action.tpl');
var layerTabMessageTemplate = require('builder/editor/layers/layer-tab-message.tpl');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var InfoboxModel = require('builder/components/infobox/infobox-model');
var REQUIRED_OPTS = [
'mapDefinitionModel',
'userActions',
'layerDefinitionModel',
'legendDefinitionsCollection',
'editorModel',
'userModel',
'configModel',
'modals',
'layerContentModel'
];
var LEGEND_TYPES = {
color: 'color',
size: 'size'
};
module.exports = CoreView.extend({
module: 'layer-content-views:legend:legends-view',
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
this._initViewState();
this._initModels();
this._initBinds();
},
render: function () {
this.clearSubViews();
this.$el.empty();
if (this._isErrored()) {
this._renderError();
} else if (this._viewState.get('isDataFiltered')) {
this._renderFilteredData();
} else {
this._initViews();
}
return this;
},
_initViewState: function () {
this._viewState = new Backbone.Model({
isDataFiltered: false
});
this._setViewValues();
},
_initModels: function () {
this._infoboxModel = new InfoboxModel({
state: this._isLayerHidden() ? 'layer-hidden' : ''
});
this._overlayModel = new Backbone.Model({
visible: this._isLayerHidden()
});
},
_initBinds: function () {
this.listenTo(this._editorModel, 'change:edition', this._changeStyle);
this.listenTo(this._layerContentModel, 'change:state', this._setViewValues);
this.listenTo(this._viewState, 'change:isDataFiltered', this.render);
},
_isLayerHidden: function () {
return this._layerDefinitionModel.get('visible') === false;
},
_onQueryChanged: function () {
if (this._isErrored()) {
this.render();
}
},
_isErrored: function () {
return this._layerContentModel.isErrored();
},
_renderError: function () {
this.$el.append(
sqlErrorTemplate({
body: _t('editor.error-query.body', {
action: actionErrorTemplate({
label: _t('editor.error-query.label')
})
})
})
);
},
_renderFilteredData: function () {
this.$el.append(
layerTabMessageTemplate({
message: _t('editor.layers.warnings.no-data.message'),
action: _t('editor.layers.warnings.no-data.action-message')
})
);
},
_initViews: function () {
var tabPaneTabs = [this._getColorTabPaneOptions(), this._getSizeTabPaneOptions()];
var tabPaneOptions = {
tabPaneOptions: {
template: TabPaneTemplate,
tabPaneItemOptions: {
tagName: 'li',
klassName: 'CDB-NavSubmenu-item'
}
},
tabPaneItemLabelOptions: {
tagName: 'button',
className: 'CDB-NavSubmenu-link u-upperCase'
}
};
this._layerTabPaneView = createTextLabelsTabPane(tabPaneTabs, tabPaneOptions);
this.$el.append(this._layerTabPaneView.render().$el);
this.addView(this._layerTabPaneView);
this._changeStyle(this._editorModel);
},
_getColorTabPaneOptions: function () {
var self = this;
return {
name: LEGEND_TYPES.color,
label: _t('editor.legend.menu-tab-pane-labels.color'),
createContentView: function () {
return new LegendColorView({
className: 'Editor-content js-type',
mapDefinitionModel: self._mapDefinitionModel,
editorModel: self._editorModel,
userActions: self._userActions,
layerContentModel: self._layerContentModel,
layerDefinitionModel: self._layerDefinitionModel,
legendDefinitionsCollection: self._legendDefinitionsCollection,
type: LEGEND_TYPES.color,
userModel: self._userModel,
configModel: self._configModel,
modals: self._modals,
overlayModel: self._overlayModel,
infoboxModel: self._infoboxModel
});
}
};
},
_getSizeTabPaneOptions: function () {
var legendType = LEGEND_TYPES.size;
var disabled = !this._isStyleCompatible(legendType);
var self = this;
return {
name: legendType,
label: _t('editor.legend.menu-tab-pane-labels.size'),
disabled: disabled,
tooltip: disabled && _t('editor.legend.menu-tab-pane-labels.size-disabled'),
createContentView: function () {
return new LegendSizeView({
className: 'Editor-content js-type',
mapDefinitionModel: self._mapDefinitionModel,
editorModel: self._editorModel,
userActions: self._userActions,
userModel: self._userModel,
configModel: self._configModel,
modals: self._modals,
layerContentModel: self._layerContentModel,
layerDefinitionModel: self._layerDefinitionModel,
legendDefinitionsCollection: self._legendDefinitionsCollection,
type: legendType,
overlayModel: self._overlayModel,
infoboxModel: self._infoboxModel
});
}
};
},
_isStyleCompatible: function (legendType) {
if (legendType === LEGEND_TYPES.size) {
var isCompatible = _.some(LegendSizeTypes, function (type) {
var isStyleCompatible = type.isStyleCompatible;
if (isStyleCompatible) {
return isStyleCompatible(this._layerDefinitionModel.styleModel);
}
return false;
}, this);
return isCompatible;
}
return true;
},
_changeStyle: function (m) {
if (this._layerTabPaneView) { this._layerTabPaneView.changeStyleMenu(m); }
},
_showHiddenLayer: function () {
var savingOptions = {
shouldPreserveAutoStyle: true
};
this._layerDefinitionModel.toggleVisible();
this._userActions.saveLayer(this._layerDefinitionModel, savingOptions);
},
_setViewValues: function () {
this._layerDefinitionModel.isDataFiltered()
.then(function (isDataFiltered) {
this._viewState.set('isDataFiltered', isDataFiltered);
}.bind(this));
}
});
@@ -0,0 +1,22 @@
var LegendTypes = require('builder/editor/layers/layer-content-views/legend/legend-types');
var styleHelper = require('builder/helpers/style');
module.exports = [
{
value: LegendTypes.NONE,
tooltipTranslationKey: 'editor.legend.tooltips.style.none',
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/none.tpl'),
label: _t('editor.legend.types.none')
}, {
value: LegendTypes.BUBBLE,
tooltipTranslationKey: 'editor.legend.tooltips.style.bubble',
legendIcon: require('builder/editor/layers/layer-content-views/legend/carousel-icons/bubble.tpl'),
label: _t('editor.legend.types.bubble'),
isStyleCompatible: function (styleModel) {
var size = styleHelper.getSize(styleModel);
if (size == null) return false;
return size && size.attribute !== undefined;
}
}
];
@@ -0,0 +1,9 @@
var LegendTypes = require('./legend-size-types');
var LegendTypeBaseView = require('builder/editor/layers/layer-content-views/legend/legend-base-type-view');
module.exports = LegendTypeBaseView.extend({
initialize: function (opts) {
this.legendTypes = LegendTypes;
LegendTypeBaseView.prototype.initialize.call(this, opts);
}
});