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,20 @@
var _ = require('underscore');
var BaseLayerViewBase = require('./base-layer-view-base');
var template = require('./image-thumbnail-layer.tpl');
module.exports = BaseLayerViewBase.extend({
_getCompiledTemplate: function () {
return template({
title: this._getImageFileName(),
desc: _t('editor.layers.image.title-label'),
imgURL: this.model.get('image')
});
},
_getImageFileName: function () {
var imageURL = this.model.get('image');
var fileNameWithParameters = _.last(imageURL.split('/'));
var fileName = fileNameWithParameters.split('?')[0];
return fileName;
}
});
@@ -0,0 +1,37 @@
var CoreView = require('backbone/core-view');
var Router = require('builder/routes/router');
/**
* Base view for all base layer views.
*/
module.exports = CoreView.extend({
module: 'editor:layers:layer-views:base-layer-view-base',
tagName: 'li',
className: 'BlockList-item BlockList-item--basemap js-layer ui-state-disabled',
events: {
'click': '_onEditBasemap'
},
initialize: function (opts) {
this.listenTo(this.model, 'change', this.render);
},
render: function () {
this.$el.html(this._getCompiledTemplate());
return this;
},
_getCompiledTemplate: function () {
throw new Error('subclasses of BasemapLayerViewBase must implement _getCompiledTemplate');
},
_onEditBasemap: function (e) {
e.stopPropagation();
Router.goToBaseMap();
}
});
@@ -0,0 +1,52 @@
/* global Image */
var BaseLayerViewBase = require('./base-layer-view-base');
var template = require('./image-thumbnail-layer.tpl');
var DEFAULT_SUBDOMAIN = 'a';
var DEFAULT_X_POSITION = 30;
var DEFAULT_Y_POSISTION = 24;
var DEFAULT_ZOOM = 6;
var DEFAULT_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAZ9JREFUWAntWUtugzAUNKbAJl1EYtcz9Ba5UE6SC+UWPUN3SNlkw78zVhJRCeIXbCup6ic5gP08Ho/x40ESBauq6iNJkgPKDpdb1j3RTuM4HlH2ZVl+JySXpukXygaksiViRVEsNd3qu65Tfd/frpdO8jxXEGO2GcTUMAxtXddnYH1qKqe1fof3IrlZpECVJA6xMgiyMdzws0N5CzTealiIlpGbBsKz77nZSYAc67ck+NIWCbouj1cFL/eNK6df/UW7FztKMT7ZTOJDDMQ5RUyJGYK2IMyBm6ax4nFQGxZBEIStWFcH2TSu3pZjiCX2StDCf1VzJLhKtkmnqOBEjFWn/0tBaaB+REoTqJkJ2wxJpM3FtPvGMgQlabrkCUEcCcF7Kf9UBT5xvN6DIZbYK8Hp7H2dR4KuSkYFo4KPKBAiYTWBmoHznvEdQpKm82ljw+I4DObElJghaJu59AWHA9qw6CMlR9+4i6mCi0UFXdRj3z+hIL8Ju040VP+TBrkjtn0bagQH3JbcSHB/+WDNCgc8r11bZOdncjPfWV/5b4gfOaaYLUG/QVoAAAAASUVORK5CYII=';
var DEFAULT_NAME = _t('editor.layers.basemap.custom-basemap');
module.exports = BaseLayerViewBase.extend({
_getCompiledTemplate: function () {
var title = this.model.getName() || DEFAULT_NAME;
var desc = _t('editor.layers.basemap.title-label');
return template({
title: title,
desc: title === desc ? '' : desc,
imgURL: this._getImageURL()
});
},
_getImageURL: function () {
var self = this;
var url = this._lowerXYZ();
var image = new Image();
image.onerror = function () {
self.$('.js-thumbnailImg').attr('src', DEFAULT_IMG);
};
image.src = url;
return url;
},
_getSubdomain: function () {
var subdomains = this.model.get('subdomains'); // eg: 'abcd' or '1234'
return (subdomains && subdomains.length) ? subdomains[0] : DEFAULT_SUBDOMAIN;
},
_lowerXYZ: function () {
return this.model.get('urlTemplate')
.replace('{s}', this._getSubdomain())
.replace('{z}', DEFAULT_ZOOM)
.replace('{x}', DEFAULT_X_POSITION)
.replace('{y}', DEFAULT_Y_POSISTION);
}
});
@@ -0,0 +1,22 @@
<div class="Editor-ListLayer-itemHeader">
<div class="Editor-ListLayer-media Editor-ListLayer-media--placeholder u-rSpace--m">
</div>
<div class="Editor-ListLayer-inner">
<div class="Editor-ListLayer-title">
<div class="Editor-ListLayer-titleText Editor-ListLayer-titleText--placeholder">
</div>
</div>
<div class="u-flex Editor-ListLayer-info Editor-ListLayer-info--placeholder u-tSpace--m">
</div>
</div>
</div>
<ul class="Editor-ListAnalysis js-analyses">
<li class="Editor-ListAnalysis-item Editor-ListAnalysis-layer--placeholder Editor-ListAnalysis-layer js-base is-base ui-draggable ui-draggable-handle">
<div class="Editor-ListAnalysis-itemInfo u-rSpace--m">
<div class="Editor-ListAnalysis-itemInfoIcon Editor-ListAnalysis-itemInfoIcon--placeholder">
</div>
</div>
<div class="Editor-ListAnalysis-itemInfoDataset--placeholder">
</div>
</li>
</ul>
@@ -0,0 +1,529 @@
var Backbone = require('backbone');
var _ = require('underscore');
var CoreView = require('backbone/core-view');
var template = require('./data-layer.tpl');
var fetchingTemplate = require('./data-layer-fetching.tpl');
var ContextMenuView = require('builder/components/context-menu/context-menu-view');
var CustomListCollection = require('builder/components/custom-list/custom-list-collection');
var renameLayer = require('builder/editor/layers/operations/rename-layer');
var DeleteLayerConfirmationView = require('builder/components/modals/remove-layer/delete-layer-confirmation-view');
var ModalExportDataView = require('builder/components/modals/export-data/modal-export-data-view');
var InlineEditorView = require('builder/components/inline-editor/inline-editor-view');
var TipsyTooltipView = require('builder/components/tipsy-tooltip-view');
var zoomToData = require('builder/editor/map-operations/zoom-to-data');
var templateInlineEditor = require('./inline-editor.tpl');
var geometryNoneTemplate = require('./geometry-none.tpl');
var geometryPointsTemplate = require('./geometry-points.tpl');
var geometryLinesTemplate = require('./geometry-lines.tpl');
var geometryPolygonsTemplate = require('./geometry-polygons.tpl');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var fetchAllQueryObjects = require('builder/helpers/fetch-all-query-objects');
var Router = require('builder/routes/router');
var IconView = require('builder/components/icon/icon-view');
var STATES = require('builder/data/query-base-status');
const { nodeHasTradeArea, nodeHasSQLFunction } = require('builder/helpers/analysis-node-utils');
var REQUIRED_OPTS = [
'userActions',
'layerDefinitionsCollection',
'modals',
'configModel',
'stateDefinitionModel',
'widgetDefinitionsCollection',
'visDefinitionModel',
'analysisDefinitionNodesCollection'
];
module.exports = CoreView.extend({
module: 'editor:layers:layer-views:data-layer-view',
tagName: 'li',
className: 'Editor-ListLayer-item js-layer',
events: {
'click': '_onEditLayer',
'click .js-base': '_onClickSource',
'click .js-title': '_onClickTitle',
'click .js-toggle-menu': '_onToggleContextMenuClicked',
'click .js-toggle': '_onToggleLayerClicked',
'click .js-analysis-node': '_onAnalysisNodeClicked'
},
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
if (!_.isFunction(opts.newAnalysesView)) throw new Error('newAnalysesView is required as a function');
this._newAnalysesView = opts.newAnalysesView;
this._styleModel = this.model.styleModel;
var nodeDefModel = this.model.getAnalysisDefinitionNodeModel();
this._queryGeometryModel = nodeDefModel.queryGeometryModel;
this._queryRowsStatus = nodeDefModel.queryRowsCollection.statusModel;
this._initViewState();
this._bindEvents();
fetchAllQueryObjects({
queryRowsCollection: nodeDefModel.queryRowsCollection,
queryGeometryModel: this._queryGeometryModel,
querySchemaModel: nodeDefModel.querySchemaModel
}).then(function () {
this.model.fetchQueryRowsIfRequired();
this._setViewState();
}.bind(this));
},
render: function () {
this.clearSubViews();
var isAnimation = this._styleModel.isAnimation();
var fetching = this._viewState.get('isFetchingRows');
if (fetching) {
this.$el.html(fetchingTemplate());
this.$el.addClass('Editor-ListLayer-item--fetching');
return this;
} else {
this.$el.removeClass('Editor-ListLayer-item--fetching');
}
this.$el.html(template({
layerId: this.model.id,
title: this.model.getName(),
color: this.model.getColor(),
isVisible: this.model.get('visible'),
isAnimated: isAnimation,
isTorque: this._isTorque(),
hasError: this._hasError(),
isCollapsed: this._isCollapsed(),
numberOfAnalyses: this.model.getNumberOfAnalyses(),
numberOfWidgets: this._widgetDefinitionsCollection.widgetsOwnedByLayer(this.model.id),
needsGeocoding: this._viewState.get('needsGeocoding'),
hasGeom: this._viewState.get('queryGeometryHasGeom'),
isEmpty: this._viewState.get('isLayerEmpty'),
brokenLayer: false
}));
this._initViews();
return this;
},
_initViewState: function () {
this._viewState = new Backbone.Model({
needsGeocoding: false,
isLayerEmpty: false,
queryGeometryHasGeom: true,
isFetchingRows: false
});
this._setViewState();
},
_isTorque: function () {
return this.model.isTorqueLayer();
},
_initViews: function () {
var geometryTemplate = this._getGeometryTemplate(this._queryGeometryModel.get('simple_geom'));
this._inlineEditor = new InlineEditorView({
template: templateInlineEditor,
renderOptions: {
title: this.model.getName()
},
onClick: this._onEditLayer.bind(this),
onEdit: this._renameLayer.bind(this)
});
this.addView(this._inlineEditor);
this.$('.js-thumbnail').append(geometryTemplate({
letter: this.model.get('letter')
}));
this.$('.js-header').html(this._inlineEditor.render().el);
this.$el.toggleClass('is-unavailable', this.model.isNew());
this.$el.toggleClass('js-sortable-item', !this._isTorque());
this.$el.toggleClass('is-animated', this._isTorque());
this.$el.toggleClass('is-empty', this._viewState.get('needsGeocoding'));
this.$('.js-thumbnail').toggleClass('is-hidden', this._isHidden());
this.$('.js-title').toggleClass('is-hidden', this._isHidden());
this.$('.js-analyses-widgets-info').toggleClass('is-hidden', this._isHidden());
if (this._isTorque()) {
var torqueTooltip = new TipsyTooltipView({
el: this.$('.js-torqueIcon'),
gravity: 's',
offset: 0
});
this.addView(torqueTooltip);
}
if (this._viewState.get('needsGeocoding')) {
var georeferenceTooltip = new TipsyTooltipView({
el: this.$('.js-geocode'),
gravity: 'w',
offset: 0
});
this.addView(georeferenceTooltip);
}
if (this._viewState.get('isLayerEmpty')) {
var warningIcon = new IconView({
placeholder: this.$el.find('.js-emptylayer'),
icon: 'warning'
});
warningIcon.render();
this.addView(warningIcon);
var emptyLayerTooltip = new TipsyTooltipView({
el: this.$el.find('.js-emptylayer'),
gravity: 'w',
title: function () {
return _t('editor.layers.layer.empty-layer');
}
});
this.addView(emptyLayerTooltip);
}
this._toggleClickEventsOnCapturePhase('remove'); // remove any if rendered previously
if (this.model.isNew()) {
this._toggleClickEventsOnCapturePhase('add');
}
if (this.model.get('source')) {
var analysesView = this._newAnalysesView(this.$('.js-analyses'), this.model);
this.addView(analysesView);
analysesView.render();
}
if (this._hasError()) {
var errorTooltip = new TipsyTooltipView({
el: this.$('.js-error'),
gravity: 's',
offset: 0,
title: function () {
return this.model.get('error') && this.model.get('error').message;
}.bind(this)
});
this.addView(errorTooltip);
}
var toggleTooltip = new TipsyTooltipView({
el: this.$('.js-toggle-menu'),
gravity: 'w',
title: function () {
return _t('more-options');
}
});
this.addView(toggleTooltip);
var toggleMenuTooltip = new TipsyTooltipView({
el: this.$('.js-toggle'),
gravity: 's',
title: function () {
return this._isHidden() ? _t('editor.layers.options.show') : _t('editor.layers.options.hide');
}.bind(this)
});
this.addView(toggleMenuTooltip);
},
_bindEvents: function () {
this.listenTo(this.model, 'change', this.render);
this.listenToOnce(this.model, 'destroy', this._onDestroy);
this.listenTo(this._queryGeometryModel, 'change:simple_geom', this._setViewState);
this.listenTo(this._queryRowsStatus, 'change:status', this._onQueryRowsStatusChanged);
this.listenTo(this._viewState, 'change', this.render);
},
_getGeometryTemplate: function (geometry) {
switch (geometry) {
case 'line':
return geometryLinesTemplate;
case 'point':
return geometryPointsTemplate;
case 'polygon':
return geometryPolygonsTemplate;
default:
return geometryNoneTemplate;
}
},
_isHidden: function () {
return !this.model.get('visible');
},
_hasError: function () {
return !!this.model.get('error');
},
_isCollapsed: function () {
return !!this.model.get('collapsed');
},
_onClickTitle: function (event) {
// event is handled with inlineEditor
event.stopPropagation();
},
_onAnalysisNodeClicked: function (event) {
event.stopPropagation();
var nodeId = event.currentTarget && event.currentTarget.dataset.analysisNodeId;
if (!nodeId) throw new Error('missing data-analysis-node-id on element to edit analysis node, the element was: ' + event.currentTarget.outerHTML);
var nodeDefModel = this._analysisDefinitionNodesCollection.get(nodeId);
var layerDefModel = this._layerDefinitionsCollection.findOwnerOfAnalysisNode(nodeDefModel);
if (!layerDefModel) throw new Error('no owning layer found for node ' + nodeId);
Router.goToAnalysisNode(this.model.get('id'), nodeId);
},
_onClickSource: function (event) {
event.stopPropagation();
Router.goToDataTab(this.model.get('id'));
},
_onEditLayer: function (event) {
event && event.stopPropagation();
var self = this;
this.model.canBeGeoreferenced()
.then(function (canBeGeoreferenced) {
if (canBeGeoreferenced) {
Router.goToAnalysisTab(self.model.get('id'));
}
});
Router.goToStyleTab(self.model.get('id')); // Speculative execution. We bet on not needing geocoding to give quick feedback to the user.
},
_onToggleCollapsedLayer: function () {
this.model.toggleCollapse();
},
_onToggleLayerClicked: function (event) {
event.stopPropagation();
var savingOptions = {
shouldPreserveAutoStyle: true
};
this.model.toggleVisible();
this._userActions.saveLayer(this.model, savingOptions);
},
_onToggleContextMenuClicked: function (event) {
event.stopPropagation();
if (this._hasContextMenu()) {
this._hideContextMenu();
} else {
this._showContextMenu({
x: event.pageX,
y: event.pageY
});
}
},
_hasContextMenu: function () {
return this._menuView;
},
_hideContextMenu: function () {
this.removeView(this._menuView);
this._menuView.clean();
delete this._menuView;
},
_getContextMenuOptions: function () {
var menuItems = [{
label: _t('editor.layers.options.edit'),
val: 'edit-layer',
action: this._onEditLayer.bind(this)
}];
if (!this._viewState.get('needsGeocoding')) {
menuItems = menuItems.concat([{
label: this._isCollapsed() ? _t('editor.layers.options.expand') : _t('editor.layers.options.collapse'),
val: 'collapse-expand-layer',
action: this._onToggleCollapsedLayer.bind(this)
}, {
label: _t('editor.layers.options.rename'),
val: 'rename-layer',
action: function () {
this._inlineEditor.edit();
}.bind(this)
}]);
if (!this._viewState.get('isLayerEmpty')) {
menuItems = menuItems.concat([
{
label: _t('editor.layers.options.export'),
val: 'export-data',
action: this._exportLayer.bind(this)
},
{
label: _t('editor.layers.options.center-map'),
val: 'center-map',
action: this._centerMap.bind(this)
}
]);
}
}
if (this.model.canBeDeletedByUser()) {
menuItems.push({
label: _t('editor.layers.options.delete'),
val: 'delete-layer',
action: this._confirmDeleteLayer.bind(this),
destructive: true
});
}
return menuItems;
},
_showContextMenu: function (position) {
var menuItems = new CustomListCollection(this._getContextMenuOptions());
var triggerElementID = 'context-menu-trigger-' + this.model.cid;
this.$('.js-toggle-menu').attr('id', triggerElementID);
this._menuView = new ContextMenuView({
collection: menuItems,
triggerElementID: triggerElementID,
position: position
});
menuItems.bind('change:selected', function (menuItem) {
menuItem.has('action') && menuItem.get('action')();
}, this);
this._menuView.model.bind('change:visible', function (model, isContextMenuVisible) {
if (this._hasContextMenu() && !isContextMenuVisible) {
this._hideContextMenu();
}
}, this);
this._menuView.show();
this.addView(this._menuView);
},
_exportLayer: function () {
var nodeDefModel = this.model.getAnalysisDefinitionNodeModel();
const { queryGeometryModel, querySchemaModel } = nodeDefModel;
const canHideColumns = nodeHasTradeArea(nodeDefModel) &&
!nodeHasSQLFunction(nodeDefModel);
this._modals.create(function (modalModel) {
return new ModalExportDataView({
fromView: 'main',
modalModel: modalModel,
queryGeometryModel,
querySchemaModel,
canHideColumns,
configModel: this._configModel,
layerModel: this.model,
filename: this.model.getName()
});
}.bind(this));
},
_confirmDeleteLayer: function () {
this._modals.create(function (modalModel) {
var deleteLayerConfirmationView = new DeleteLayerConfirmationView({
userActions: this._userActions,
modals: this._modals,
layerModel: this.model,
modalModel: modalModel,
visDefinitionModel: this._visDefinitionModel,
widgetDefinitionsCollection: this._widgetDefinitionsCollection
});
return deleteLayerConfirmationView;
}.bind(this));
},
_renameLayer: function () {
var newName = this._inlineEditor.getValue();
if (newName !== '') {
// Optimistic
this._onSaveSuccess(newName);
renameLayer({
newName: newName,
userActions: this._userActions,
layerDefinitionsCollection: this._layerDefinitionsCollection,
layerDefinitionModel: this.model,
onError: this._onSaveError.bind(this)
});
}
},
_onSaveSuccess: function (newName) {
this.$('.js-title').text(newName).show();
this._inlineEditor.hide();
},
_onSaveError: function (oldName) {
this.$('.js-title').text(oldName).show();
this._inlineEditor.hide();
},
_onDestroy: function () {
this.clean();
},
_disableEventsOnCapturePhase: function (evt) {
evt.stopPropagation();
evt.preventDefault();
},
_toggleClickEventsOnCapturePhase: function (str) {
var addOrRemove = str === 'add'
? 'add'
: 'remove';
this.el[addOrRemove + 'EventListener']('click', this._disableEventsOnCapturePhase, true);
},
_centerMap: function () {
var nodeModel = this.model.getAnalysisDefinitionNodeModel();
var query = nodeModel.querySchemaModel.get('query');
zoomToData(this._configModel, this._stateDefinitionModel, query);
},
_isFetchingRows: function () {
var nodeDefModel = this.model.getAnalysisDefinitionNodeModel();
var queryRowsStatus = nodeDefModel.queryRowsCollection.statusModel;
return queryRowsStatus.get('status') === STATES.fetching;
},
_onQueryRowsStatusChanged: function () {
this._viewState.set('isFetchingRows', this._isFetchingRows());
this._setViewState();
},
_setViewState: function () {
var self = this;
var georeferencePromise = this.model.canBeGeoreferenced();
var isLayerEmptyPromise = this.model.isEmptyAsync();
var hasGeomPromise = this._queryGeometryModel.hasValueAsync();
Promise.all([georeferencePromise, isLayerEmptyPromise, hasGeomPromise])
.then(function (values) {
self._viewState.set({
needsGeocoding: values[0],
isLayerEmpty: values[1],
queryGeometryHasGeom: values[2],
isFetchingRows: self._isFetchingRows()
});
});
},
clean: function () {
this._toggleClickEventsOnCapturePhase('remove');
CoreView.prototype.clean.apply(this);
}
});
@@ -0,0 +1,108 @@
<% if (hasError) { %>
<div class="Editor-ListLayer-itemError js-error"></div>
<% } %>
<% if (!isTorque) { %>
<div class="Editor-ListLayer-dragIcon">
<div class="CDB-Shape">
<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>
<% } %>
<div class="Editor-ListLayer-itemHeader">
<div class="Editor-ListLayer-media u-rSpace--m js-thumbnail" style="background: <%- color %>; color: #fff">
</div>
<div class="Editor-ListLayer-inner">
<div class="Editor-ListLayer-title">
<div class="Editor-ListLayer-titleText js-Editor-ListLayer-titleText js-header">
<h2 class="CDB-Text CDB-Size-large u-ellipsis">
<%- title %>
</h2>
</div>
<ul class="Editor-HeaderInfo-actions">
<% if (isTorque) { %>
<li class="Editor-HeaderInfo-actionsItem u-rSpace">
<% if (isAnimated) { %>
<svg class="js-torqueIcon" width="19px" height="8px" viewBox="222 24 19 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-tooltip="<%- _t('editor.layers.layer.animated') %>">
<g id="Animated-Icon" opacity="0.6" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(222.000000, 24.000000)">
<rect id="Rectangle-649" fill="#2E3C43" x="11" y="0" width="8" height="8" rx="4"></rect>
<rect id="Rectangle-649" fill="#2E3C43" opacity="0.5" x="5" y="0" width="8" height="8" rx="4"></rect>
<rect id="Rectangle-649" fill="#2E3C43" opacity="0.2" x="0" y="0" width="8" height="8" rx="4"></rect>
</g>
</svg>
<% } else { %>
<svg class="js-torqueIcon" width="31px" height="17px" viewBox="563 512 31 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-tooltip="<%- _t('editor.layers.layer.heatmap') %>">
<g id="Group" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(563.000000, 512.000000)">
<ellipse id="Oval-120" fill="#E6E8E8" transform="translate(27.020000, 12.197917) rotate(-90.000000) translate(-27.020000, -12.197917) " cx="27.02" cy="12.1979167" rx="3.875" ry="3.84"></ellipse>
<path d="M26.93,13.0729167 C27.3442136,13.0729167 27.68,12.7371302 27.68,12.3229167 C27.68,11.9087031 27.3442136,11.5729167 26.93,11.5729167 C26.5157864,11.5729167 26.18,11.9087031 26.18,12.3229167 C26.18,12.7371302 26.5157864,13.0729167 26.93,13.0729167 Z" id="Oval-120-Copy-2" fill="#828A8F" opacity="0.8" transform="translate(26.930000, 12.322917) rotate(-90.000000) translate(-26.930000, -12.322917) "></path>
<ellipse id="Oval-120" fill="#E6E8E8" transform="translate(8.140000, 8.000000) rotate(-90.000000) translate(-8.140000, -8.000000) " cx="8.14" cy="8" rx="7.75" ry="7.68"></ellipse>
<path d="M7.96,10.75 C9.34071187,10.75 10.46,9.63071187 10.46,8.25 C10.46,6.86928813 9.34071187,5.75 7.96,5.75 C6.57928813,5.75 5.46,6.86928813 5.46,8.25 C5.46,9.63071187 6.57928813,10.75 7.96,10.75 Z" id="Oval-120-Copy-2" fill="#828A8F" transform="translate(7.960000, 8.250000) rotate(-90.000000) translate(-7.960000, -8.250000) "></path>
<path d="M15.1403347,6.71285923 C15.4606435,9.05621552 17.487459,10.8625 19.94,10.8625 C22.6151293,10.8625 24.78375,8.7134668 24.78375,6.0625 C24.78375,3.4115332 22.6151293,1.2625 19.94,1.2625 C17.2648707,1.2625 15.09625,3.4115332 15.09625,6.0625 C15.09625,6.28307774 15.1112641,6.50018043 15.1403347,6.71285923 Z" id="Oval-120" fill="#E6E8E8" transform="translate(19.940000, 6.062500) rotate(-90.000000) translate(-19.940000, -6.062500) "></path>
<path d="M20.64,7.90625 C21.4684271,7.90625 22.14,7.23467712 22.14,6.40625 C22.14,5.57782288 21.4684271,4.90625 20.64,4.90625 C19.8115729,4.90625 19.14,5.57782288 19.14,6.40625 C19.14,7.23467712 19.8115729,7.90625 20.64,7.90625 Z" id="Oval-120-Copy-2" fill="#828A8F" opacity="0.8" transform="translate(20.640000, 6.406250) rotate(-90.000000) translate(-20.640000, -6.406250) "></path>
<path d="M13.5625,2.88 C13.5625,2.88 16.1458333,5.12 18.0833333,2.56 C17.4375,4.16 17.1145833,5.44 17.1145833,5.44 L16.46875,6.72 L14.2083333,4.8 L13.5625,2.88 Z" id="Path-494" fill="#E6E8E8"></path>
<path d="M22.3894032,6.40571996 C22.3894032,6.40571996 24.9727365,8.64571996 26.9102365,6.08571996 C26.2644032,7.68571996 25.9414865,8.96571996 25.9414865,8.96571996 L25.2956532,10.24572 L23.0352365,8.32571996 L22.3894032,6.40571996 Z" id="Path-494" fill="#E6E8E8" transform="translate(24.649820, 8.165720) rotate(52.000000) translate(-24.649820, -8.165720) "></path>
<path d="M20.6462245,8.51753488 C20.6462245,8.51753488 23.9604656,11.3038091 25.8979656,8.74380905 C25.2521323,10.3438091 25.078218,11.598674 25.078218,11.598674 L24.4323847,12.878674 L21.1028976,9.87517984 L20.6462245,8.51753488 Z" id="Path-494" fill="#E6E8E8" transform="translate(23.272095, 10.698104) rotate(-135.000000) translate(-23.272095, -10.698104) "></path>
<path d="M18.2927779,9.85808612 C18.2927779,9.85808612 15.6067281,8.91370489 14.3461002,11.8663856 C14.5856745,10.1576712 14.5893391,8.83757209 14.5893391,8.83757209 L14.4253034,7.30493626 L14.7514729,5.70339822 L18.2927779,9.85808612" id="Path-494" fill="#E6E8E8"></path>
<path d="" id="Path-499" stroke="#979797" stroke-width="0.64"></path>
<polygon id="Path-500" fill="#828A8F" points="9.94618849 9.56 11.6875 7.72609277 9.6875 6.56"></polygon>
</g>
</svg>
<% } %>
</li>
<% } %>
<li class="Editor-HeaderInfo-actionsItem CDB-Shape">
<% if (hasGeom) { %>
<button class="js-toggle">
<% if (isVisible) { %>
<i class="CDB-IconFont CDB-IconFont-view u-actionTextColor"></i>
<% } else { %>
<i class="CDB-IconFont CDB-IconFont-hide u-actionTextColor"></i>
<% } %>
</button>
<% } else if (brokenLayer) { %>
<svg class="js-warningIcon" xmlns="http://www.w3.org/2000/svg" width="14" height="12" viewBox="0 0 14 12" data-tooltip="<%- _t('editor.layers.georeference.visualize') %>"><path fill="#FFB300" fill-rule="evenodd" d="M5.012 1.48C6.11-.444 7.887-.45 8.988 1.48l4.526 7.92c.82 1.436.15 2.6-1.523 2.6H2.01C.346 12-.333 10.83.485 9.4l4.526-7.92zM1.354 9.895C.917 10.66 1.116 11 2.01 11h9.98c.903 0 1.097-.333.656-1.104L8.12 1.976C7.404.72 6.596.722 5.88 1.975l-4.526 7.92zM6 9h2v1H6V9zm0-5h2v4H6V4z"/></svg>
<% } %>
</li>
<% if (isEmpty) { %>
<li class="Editor-HeaderInfo-emptyLayer js-emptylayer"></li>
<% } %>
<li class="Editor-HeaderInfo-actionsItem CDB-Shape">
<button class="CDB-Shape-threePoints is-blue is-small js-toggle-menu">
<div class="CDB-Shape-threePointsItem"></div>
<div class="CDB-Shape-threePointsItem"></div>
<div class="CDB-Shape-threePointsItem"></div>
</button>
</li>
</ul>
</div>
<div class="u-flex Editor-ListLayer-info js-analyses-widgets-info">
<span class="CDB-Text CDB-Size-small u-secondaryTextColor u-upperCase u-rSpace--m">
<%- _t('editor.layers.layer.analyses-count', { smart_count: numberOfAnalyses }) %>
</span>
<span class="CDB-Text CDB-Size-small u-secondaryTextColor u-upperCase">
<%- _t('editor.layers.layer.widgets-count', { smart_count: numberOfWidgets }) %>
</span>
</div>
</div>
</div>
<% // Show this for regular layers or ghost nodes %>
<% if (hasGeom || brokenLayer || !needsGeocoding) { %>
<ul class="Editor-ListAnalysis js-analyses <%- isVisible ? '' : 'is-hidden' %> <%- isCollapsed ? 'is-collapsed' : '' %>"></ul>
<% } %>
<% if (needsGeocoding) { %>
<div class="u-tSpace--m">
<span class="CDB-Text CDB-Size-medium u-secondaryTextColor">
<%- _t('editor.layers.layer.geocode-text') %>
</span>
<div class="u-flex u-justifyEnd u-tSpace--m">
<button data-tooltip="<%- _t('editor.layers.layer.geocode-tooltip') %>" class="CDB-Button CDB-Button--small CDB-Button--primary js-geocode">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-small"><%- _t('editor.layers.layer.geocode') %></span>
</button>
</div>
</div>
<% } %>
@@ -0,0 +1,111 @@
var $ = require('jquery');
var DataLayerView = require('./data-layer-view');
var template = require('./data-layer.tpl');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var geometryNoneTemplate = require('./geometry-none.tpl');
var TipsyTooltipView = require('builder/components/tipsy-tooltip-view');
var defaultLayerAnalysisView = require('builder/editor/layers/analysis-views/default-layer-analysis-view.tpl');
var BROKEN_NODE_LAYER_COLOR = '#CCC';
var REQUIRED_OPTS = [
'userActions',
'layerDefinitionsCollection',
'modals',
'configModel',
'stateDefinitionModel',
'widgetDefinitionsCollection',
'visDefinitionModel',
'analysisDefinitionNodesCollection'
];
module.exports = DataLayerView.extend({
tagName: 'li',
className: 'Editor-ListLayer-item',
events: {
'click .js-toggle-menu': '_onToggleContextMenuClicked'
},
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
},
render: function () {
this.clearSubViews();
var m = this.model;
var isTorque = m.isTorqueLayer();
var isAnimation = this.model.styleModel.isAnimation();
this.$el.html(template({
layerId: m.id,
title: m.getName(),
color: BROKEN_NODE_LAYER_COLOR,
isVisible: true,
isAnimated: isAnimation,
isTorque: isTorque,
hasError: false,
isCollapsed: false,
numberOfAnalyses: m.getNumberOfAnalyses(),
numberOfWidgets: this._widgetDefinitionsCollection.widgetsOwnedByLayer(m.id),
needsGeocoding: false,
hasGeom: false,
brokenLayer: true,
isEmpty: false
}));
this.$('.js-thumbnail').append(
geometryNoneTemplate({
letter: m.get('letter')
})
);
// Displaying errored node
var $nodeAnalysisItem = $('<li>').addClass('Editor-ListAnalysis-item Editor-ListAnalysis-layer');
$nodeAnalysisItem.append(
defaultLayerAnalysisView({
title: _t('editor.layers.errors.broken-node'),
id: this.model.get('source'),
bgColor: BROKEN_NODE_LAYER_COLOR,
isDone: true,
hasError: false
})
);
this.$('.js-analyses').append($nodeAnalysisItem);
this.$el.addClass('is-errored');
this.$el.removeClass('js-sortable-item');
this.$el.toggleClass('is-animated', isTorque);
var errorTooltip = new TipsyTooltipView({
el: this.$('.js-warningIcon'),
gravity: 's',
offset: 0,
title: function () {
return _t('editor.layers.errors.non-existent-node', { nodeId: this.model.get('source') });
}.bind(this)
});
this.addView(errorTooltip);
return this;
},
_getContextMenuOptions: function () {
return [{
label: _t('editor.layers.options.delete-and-reload'),
val: 'delete-layer',
action: function () {
this.listenTo(this.model, 'destroy', this._reloadApplication);
this._confirmDeleteLayer();
}.bind(this),
destructive: true
}];
},
_reloadApplication: function () {
window.location.reload();
}
});
@@ -0,0 +1,3 @@
<p class="CDB-Text CDB-Size-large is-semibold u-upperCase"><%- letter %> <svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M8.30379432,3.06016671 C8.11128812,2.75281724 8,2.38940498 8,2 C8,0.8954305 8.8954305,0 10,0 C11.1045695,0 12,0.8954305 12,2 C12,3.1045695 11.1045695,4 10,4 C9.70653076,4 9.42782451,3.93679216 9.17675238,3.82324762 L3.82324762,9.17675238 C3.93679216,9.42782451 4,9.70653076 4,10 C4,11.1045695 3.1045695,12 2,12 C0.8954305,12 0,11.1045695 0,10 C0,8.8954305 0.8954305,8 2,8 C2.38940498,8 2.75281724,8.11128812 3.06016671,8.30379432 L8.30379432,3.06016671 Z" stroke="none" fill="#FFFFFF" fill-rule="evenodd"></path>
</svg></p>
@@ -0,0 +1 @@
<p class="CDB-Text CDB-Size-large is-semibold u-upperCase"><%- letter %></p>
@@ -0,0 +1,7 @@
<p class="CDB-Text CDB-Size-large is-semibold u-upperCase"><%- letter %> <svg width="12px" height="12px" viewBox="589 382 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(589.000000, 382.000000)">
<circle fill="#FFFFFF" cx="2" cy="2" r="2"></circle>
<circle fill="#FFFFFF" cx="2" cy="10" r="2"></circle>
<circle fill="#FFFFFF" cx="10" cy="10" r="2"></circle>
</g>
</svg></p>
@@ -0,0 +1,9 @@
<p class="CDB-Text CDB-Size-large is-semibold u-upperCase"><%- letter %> <svg width="12px" height="12px" viewBox="589 382 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(589.000000, 382.000000)">
<path d="M1,2 L1,2 L2,1 L2,11 L1,10 L11,10 L10,11 L10,1 L11,2 L1,2 Z M1,1 L11,1 L11,11 L1,11 L1,1 L1,1 Z" id="Rectangle-2" fill="#FFFFFF"></path>
<circle fill="#FFFFFF" cx="2" cy="2" r="2"></circle>
<circle fill="#FFFFFF" cx="10" cy="2" r="2"></circle>
<circle fill="#FFFFFF" cx="2" cy="10" r="2"></circle>
<circle fill="#FFFFFF" cx="10" cy="10" r="2"></circle>
</g>
</svg></p>
@@ -0,0 +1,37 @@
var BaseLayerViewBase = require('./base-layer-view-base');
var template = require('./image-thumbnail-layer.tpl');
module.exports = BaseLayerViewBase.extend({
initialize: function (opts) {
BaseLayerViewBase.prototype.initialize.apply(this, arguments);
if (!opts.configModel) throw new Error('configModel is required');
this._configModel = opts.configModel;
},
_getCompiledTemplate: function () {
return template({
title: this._getTitle(),
desc: _t('editor.layers.gmaps.title-label'),
imgURL: this._getImageURL()
});
},
_getImageURL: function () {
var imageName = this.model.get('baseType');
if (this.model.get('baseName')) {
imageName = imageName + '_' + this.model.get('baseName');
}
var imageURL = [
this._configModel.get('app_assets_base_url'),
'unversioned/images/google-maps-basemap-icons',
imageName + '.jpg'
].join('/');
return imageURL;
},
_getTitle: function () {
return this.model.get('name').replace('GMaps ', '');
}
});
@@ -0,0 +1,7 @@
<div class="BlockList-media u-rSpace--xl js-thumbnail">
<img src="<%- imgURL %>" class="BlockList-mediaImg js-thumbnailImg" />
</div>
<div class="BlockList-inner">
<h2 class="BlockList-titleText CDB-Text CDB-Size-medium u-ellipsis js-title"><%- title %></h2>
<p class="CDB-Text CDB-Size-small u-secondaryTextColor u-upperCase"><%- desc %></p>
</div>
@@ -0,0 +1,4 @@
<h2 class="Inline-editor">
<div class="CDB-Text CDB-Size-large 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,35 @@
var CoreView = require('backbone/core-view');
var template = require('./image-thumbnail-layer.tpl');
module.exports = CoreView.extend({
module: 'editor:layers:layer-views:labels-layer-view',
tagName: 'li',
className: 'BlockList-item BlockList-item--noAction js-layer ui-state-disabled',
initialize: function (opts) {
this.listenTo(this.model, 'change', this.render);
},
render: function () {
var desc = _t('editor.layers.labels.title-label');
var title = this.model.getName() || desc;
this.$el.html(template({
title: title,
desc: title === desc ? '' : desc,
imgURL: this._getImageURL()
}));
return this;
},
_getImageURL: function () {
return this.model.get('urlTemplate')
.replace('{s}', 'a')
.replace('{z}', 6)
.replace('{x}', 30)
.replace('{y}', 24);
}
});
@@ -0,0 +1,15 @@
var BaseLayerViewBase = require('./base-layer-view-base');
var template = require('./plain-color-layer.tpl');
module.exports = BaseLayerViewBase.extend({
_getCompiledTemplate: function () {
var desc = _t('editor.layers.color.title-label');
var title = this.model.get('color') || desc;
return template({
title: title,
desc: title === desc ? '' : desc,
color: this.model.get('color')
});
}
});
@@ -0,0 +1,6 @@
<div class="BlockList-media u-rSpace--xl js-thumbnail" style="background-color: <%- color %>">
</div>
<div class="BlockList-inner">
<h2 class="BlockList-titleText CDB-Text CDB-Size-medium u-ellipsis js-title"><%- title %></h2>
<p class="CDB-Text CDB-Size-small u-secondaryTextColor u-upperCase"><%- desc %></p>
</div>