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,22 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-column-included') %>
</p>
<ul class="Onboarding-list">
<% if (aggregate_function === 'count') { %>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">count_vals</div>
</li>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">count_vals_density</div>
</li>
<% } else {%>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue"><%- aggregate_function %>_<%- aggregate_column %></div>
</li>
<% } %>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.aggregate-intersection.description') %>
</p>
@@ -0,0 +1,18 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.geometries-updated') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">the_geom</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.area-of-influence.the-geom') %></p>
</li>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.area-of-influence.description') %>
</p>
<p class="CDB-Text Onboarding-description">
<a href="https://carto.com/learn/guides/analysis/areas-of-influence" class="Onboarding-readMore" target="_blank"><%- _t('analyses-onboarding.learn-more') %></a>
</p>
@@ -0,0 +1,30 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-columns-created') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">the_geom</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.centroid.the-geom') %></p>
</li>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">value</div>
<p class="CDB-Text Onboarding-description">
<% if (aggregation) { %>
<%- _t('analyses-onboarding.centroid.aggregated-value') %>
<% } else { %>
<%- _t('analyses-onboarding.centroid.non-aggregated-value') %>
<% } %>
</p>
</li>
<% if (category_column) { %>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">category</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.centroid.category') %></p>
</li>
<% } %>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.centroid.description') %>
</p>
@@ -0,0 +1,18 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-columns-created') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">the_geom</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.closest.the-geom') %></p>
</li>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">source_cdb_id</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.closest.source_cdb_id') %></p>
</li>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.closest.description') %>
</p>
@@ -0,0 +1,18 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.geometries-updated') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">the_geom</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.connect-with-lines.the-geom') %></p>
</li>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.connect-with-lines.' + type) %>
</p>
<p class="CDB-Text Onboarding-description">
<a href="https://carto.com/learn/guides/analysis/connect-with-lines" class="Onboarding-readMore" target="_blank"><%- _t('analyses-onboarding.learn-more') %></a>
</p>
@@ -0,0 +1,18 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-column-included') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue"><%- final_column %></div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.data-observatory-measure.custom-column') %></p>
</li>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.data-observatory-measure.description') %>
</p>
<p class="CDB-Text Onboarding-description">
<a href="https://carto.com/learn/guides/analysis/enrich-from-data-observatory" class="Onboarding-readMore" target="_blank"><%- _t('analyses-onboarding.learn-more') %></a>
</p>
@@ -0,0 +1,21 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-columns-included') %>
</p>
<ul class="Onboarding-list">
<% _.each(column_names, function (column) { %>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue"><%- column %></div>
</li>
<% }); %>
</ul>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.data-observatory-multiple-measures.custom-columns') %>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.data-observatory-multiple-measures.description') %>
</p>
<p class="CDB-Text Onboarding-description">
<a href="https://carto.com/learn/guides/analysis/enrich-from-data-observatory" class="Onboarding-readMore" target="_blank"><%- _t('analyses-onboarding.learn-more') %></a>
</p>
@@ -0,0 +1,3 @@
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.filter-by-node-column.description') %>
</p>
@@ -0,0 +1,7 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-columns-created') %>
</p>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.filter.description') %>
</p>
@@ -0,0 +1,18 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.geometries-updated') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">the_geom</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.georeference.the-geom') %></p>
</li>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.georeference.description') %>
</p>
<p class="CDB-Text Onboarding-description">
<a href="https://carto.com/learn/guides/analysis/georeference" class="Onboarding-readMore" target="_blank"><%- _t('analyses-onboarding.learn-more') %></a>
</p>
@@ -0,0 +1,24 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.geometries-updated') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">the_geom</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.group-points.the-geom') %></p>
</li>
<% if (category_column) { %>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue"><%- category_column %></div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.group-points.category') %></p>
</li>
<% } %>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.group-points.description', { method: _t('analyses.' + type + '.title') }) %>
</p>
<p class="CDB-Text Onboarding-description">
<a href="http://postgis.net/docs/manual-2.2/" class="Onboarding-readMore" target="_blank"><%- _t('analyses-onboarding.read-more') %></a>
</p>
@@ -0,0 +1,18 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-column-included') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">source_cartodb_id</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.intersection.source-cartodb-id') %></p>
</li>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.intersection.description') %>
</p>
<p class="CDB-Text Onboarding-description">
<a href="https://carto.com/learn/guides/analysis/intersect-second-layer" class="Onboarding-readMore" target="_blank"><%- _t('analyses-onboarding.learn-more') %></a>
</p>
@@ -0,0 +1,14 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-column-added') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">cluster_no</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.kmeans.cluster-no', { clusters: clusters }) %></p>
</li>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.kmeans.description') %>
</p>
@@ -0,0 +1,11 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-columns-included-based-on-input') %>
</p>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.merge.description') %>
</p>
<p class="CDB-Text Onboarding-description">
<a href="https://carto.com/learn/guides/analysis/join-column-from-second-layer" class="Onboarding-readMore" target="_blank"><%- _t('analyses-onboarding.learn-more') %></a>
</p>
@@ -0,0 +1,30 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-columns-included') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">quads</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.moran.quads') %></p>
</li>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">significance</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.moran.significance') %></p>
</li>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">moran</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.moran.moran') %></p>
</li>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">vals</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.moran.vals') %></p>
</li>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.moran.description') %>
</p>
<p class="CDB-Text Onboarding-description">
<a href="https://carto.com/learn/guides/analysis/detect-outliers-and-clusters" class="Onboarding-readMore" target="_blank"><%- _t('analyses-onboarding.learn-more') %></a>
</p>
@@ -0,0 +1,7 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.no-new-columns') %>
</p>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.sampling.description', { percentage: Math.round(sampling * 100) }) %>
</p>
@@ -0,0 +1,30 @@
<p class="CDB-Text Onboarding-headerDescription">
<%- _t('analyses-onboarding.new-columns-included') %>
</p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">trend</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.spatial-markov-trend.trend') %></p>
</li>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">trend_up</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.spatial-markov-trend.trend_up') %></p>
</li>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">trend_down</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.spatial-markov-trend.trend_down') %></p>
</li>
<li class="Onboarding-listItem">
<div class="Onboarding-listItemValue">volatility</div>
<p class="CDB-Text Onboarding-description"><%- _t('analyses-onboarding.spatial-markov-trend.volatility') %></p>
</li>
</ul>
<p class="CDB-Text Onboarding-description">
<%- _t('analyses-onboarding.spatial-markov-trend.description') %>
</p>
<p class="CDB-Text Onboarding-description">
<a href="https://carto.com/learn/guides/analysis/predict-trends-and-volatility" class="Onboarding-readMore" target="_blank"><%- _t('analyses-onboarding.learn-more') %></a>
</p>
@@ -0,0 +1,70 @@
var LocalStorage = require('builder/components/local-storage/local-storage');
var AnalysisOnboardingView = require('builder/components/onboardings/analysis/analysis-view');
var Analyses = require('builder/data/analyses');
var BASE_STORAGE_KEY = 'onboarding';
var launcher = (function () {
var onboardings;
var userModel;
var editorModel;
var visDefinitionModel;
function init (opts) {
if (!onboardings && !opts) {
throw new Error('onboardings is required');
}
if (!userModel && !opts) {
throw new Error('userModel is required');
}
if (!visDefinitionModel && !opts) {
throw new Error('visDefinitionModel is required');
}
if (!onboardings && opts && opts.onboardings) {
onboardings = opts.onboardings;
}
if (!userModel && opts && opts.userModel) {
userModel = opts.userModel;
}
if (!visDefinitionModel && opts && opts.visDefinitionModel) {
visDefinitionModel = opts.visDefinitionModel;
}
editorModel = onboardings.editorModel;
}
return {
init: function (opts) {
init(opts);
var storageKey = BASE_STORAGE_KEY + '.' + visDefinitionModel.get('id');
LocalStorage.init(storageKey, {
userModel: userModel
});
},
launch: function (type, model) {
var genericType = Analyses.getAnalysisByType(type).genericType || type;
if (!LocalStorage.get(genericType) && genericType) {
onboardings.create(function (modalModel) {
return new AnalysisOnboardingView({
modalModel: modalModel,
userModel: userModel,
editorModel: editorModel,
model: model,
visDefinitionModel: visDefinitionModel
});
});
}
}
};
})();
module.exports = launcher;
@@ -0,0 +1,84 @@
var LocalStorage = require('builder/components/local-storage/local-storage');
var CoreView = require('backbone/core-view');
var template = require('./analysis-view.tpl');
var Analyses = require('builder/data/analyses');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var BASE_STORAGE_KEY = 'onboarding';
var REQUIRED_OPTS = [
'modalModel',
'userModel',
'editorModel',
'visDefinitionModel'
];
module.exports = CoreView.extend({
className: 'AnalysisCompletionDetails is-opening',
events: {
'click .js-close': '_close',
'click .js-style': '_onStyle'
},
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
var storageKey = BASE_STORAGE_KEY + '.' + this._visDefinitionModel.get('id');
LocalStorage.init(storageKey, {
userModel: this._userModel
});
this._initBinds();
},
render: function () {
this.$el.html(template({
type: this._getGenericAnalysisType()
}));
var onboardingTemplate = this._typeDef().onboardingTemplate;
var html = onboardingTemplate && onboardingTemplate(this.model.attributes);
this.$('.js-content').html(html);
this._onChangeEditorModelEdition(this._editorModel);
return this;
},
_initBinds: function () {
this.listenTo(this.model, 'destroy', this._close);
this.listenTo(this._editorModel, 'change:edition', this._onChangeEditorModelEdition);
this.add_related_model(this._editorModel);
},
_onChangeEditorModelEdition: function (mdl) {
var isEditing = !!mdl.get('edition');
this.$el.toggleClass('is-editing', isEditing);
},
_close: function () {
this._forget();
this.trigger('close', this);
},
_onStyle: function () {
this._forget();
this.trigger('customEvent', 'style', this);
},
_forget: function () {
LocalStorage.set(this._getGenericAnalysisType(), true);
},
_typeDef: function (type) {
type = type || this.model.get('type');
return Analyses.getAnalysisByType(type);
},
_getGenericAnalysisType: function () {
var typeDef = this._typeDef();
return typeDef && typeDef.genericType || this.model.get('type');
}
});
@@ -0,0 +1,22 @@
<div class="Onboarding-fake"></div>
<div class="Onboarding-contentWrapper">
<div class="Onboarding-body">
<p class="CDB-Text Onboarding-headerTitle"><%- _t('analyses-onboarding.' + type + '.title') %></p>
<p class="CDB-Text Onboarding-headerText"><%- _t('analyses-onboarding.finished') %></p>
<div class="js-content"></div>
<div class="Onboarding-footer">
<div class="Onboarding-footerButtons">
<button class="CDB-Button CDB-Button--secondary CDB-Button--white CDB-Button--big Onboarding-footer--marginRight js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('analyses-onboarding.done') %></span>
</button>
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-style">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('analyses-onboarding.style-analysis') %></span>
</button>
</div>
</div>
</div>
</div>
@@ -0,0 +1,128 @@
var $ = require('jquery');
var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
var template = require('./builder-view.tpl');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var GAPusher = require('builder/helpers/ga-pusher');
var BUILDER_KEY = 'onboarding';
var LEFT_KEY_CODE = 37;
var RIGHT_KEY_CODE = 39;
var REQUIRED_OPTS = [
'userModel',
'onboardingNotification',
'editorModel'
];
module.exports = CoreView.extend({
className: 'BuilderOnboarding is-step0 is-opening',
events: {
'click .js-start': '_onClickNext',
'click .js-next': '_onClickNext',
'click .js-close': '_close'
},
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
this._initModels();
this._initBinds();
},
render: function () {
this.$el.html(template({
name: this._userModel.get('name') || this._userModel.get('username')
}));
return this;
},
_initModels: function () {
this.model = new Backbone.Model({
step: 0
});
},
_initBinds: function () {
this._keyDown = this._onKeyDown.bind(this);
$(document).on('keydown', this._keyDown);
this.listenTo(this.model, 'change:step', this._onChangeStep);
this.listenTo(this.model, 'destroy', this._close);
this.listenTo(this._editorModel, 'change:edition', this._changeEdition);
},
_changeEdition: function (mdl) {
var isEditing = !!mdl.get('edition');
this.$el.toggleClass('is-editing', isEditing);
},
_prev: function () {
if (this._currentStep() >= 1) {
this.model.set('step', this._currentStep() - 1);
}
},
_next: function () {
if (this._currentStep() <= 3) {
this.model.set('step', this._currentStep() + 1);
}
},
_currentStep: function () {
return this.model.get('step');
},
_onClickNext: function () {
this._next();
},
_onChangeStep: function () {
var self = this;
this.$el.removeClass('is-step' + this.model.previous('step'), function () {
self.$el.addClass('is-step' + self._currentStep());
});
this.$('.js-step').removeClass('is-step' + this.model.previous('step'), function () {
self.$('.js-step').addClass('is-step' + self._currentStep());
});
},
_close: function () {
this._forget();
GAPusher({
eventName: 'send',
hitType: 'event',
eventCategory: 'Edit your Map',
eventAction: 'click',
eventLabel: 'Builder'
});
this.trigger('close', this);
},
_onKeyDown: function (e) {
e.stopPropagation();
if (e.which === LEFT_KEY_CODE) {
this._prev();
} else if (e.which === RIGHT_KEY_CODE) {
this._next();
}
},
_forget: function () {
this._onboardingNotification.setKey(BUILDER_KEY, true);
this._onboardingNotification.save();
},
clean: function () {
$(document).off('keydown', this._keyDown);
CoreView.prototype.clean.apply(this);
}
});
@@ -0,0 +1,83 @@
<div class="BuilderOnboarding-pad"></div>
<div class="BuilderOnboarding-pad2"></div>
<div class="BuilderOnboarding-contentWrapper is-step0 js-step">
<div class="BuilderOnboarding-body">
<div class="BuilderOnboarding-header is-step0">
<p class="CDB-Text Onboarding-headerTitle"><%- _t('builder-onboarding.title')%></p>
<p class="CDB-Text Onboarding-headerText"><%- name %></p>
<p class="CDB-Text BuilderOnboarding-description">
<%- _t('builder-onboarding.description')%>
</p>
</div>
<div class="BuilderOnboarding-footer is-step0">
<div class="BuilderOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--secondary CDB-Button--white CDB-Button--big Onboarding-footer--marginRight js-start">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('builder-onboarding.take-tour')%></span>
</button>
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-close track-onboarding--editMap">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('builder-onboarding.edit-map')%></span>
</button>
</div>
</div>
<div class="BuilderOnboarding-step is-step1">
<p class="CDB-Text Onboarding-headerTitle">1/4</p>
<p class="CDB-Text Onboarding-headerText"><%- _t('builder-onboarding.toolbar.title')%></p>
<p class="CDB-Text BuilderOnboarding-description">
<%- _t('builder-onboarding.toolbar.description')%>
</p>
</div>
<div class="BuilderOnboarding-step is-step2">
<p class="CDB-Text Onboarding-headerTitle">2/4</p>
<p class="CDB-Text Onboarding-headerText"><%- _t('builder-onboarding.configurator.title')%></p>
<p class="CDB-Text BuilderOnboarding-description">
<%- _t('builder-onboarding.configurator.description')%>
</p>
</div>
<div class="BuilderOnboarding-step is-step3">
<p class="CDB-Text Onboarding-headerTitle">3/4</p>
<p class="CDB-Text Onboarding-headerText"><%- _t('builder-onboarding.map.title')%></p>
<p class="CDB-Text BuilderOnboarding-description">
<%- _t('builder-onboarding.map.description')%>
</p>
</div>
<div class="BuilderOnboarding-step is-step4">
<p class="CDB-Text Onboarding-headerTitle">4/4</p>
<p class="CDB-Text Onboarding-headerText"><%- _t('builder-onboarding.widgets.title')%></p>
<p class="CDB-Text BuilderOnboarding-description">
<%- _t('builder-onboarding.widgets.description')%>
</p>
</div>
<div class="BuilderOnboarding-footer is-step1 is-step2 is-step3">
<div class="BuilderOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--secondary CDB-Button--white CDB-Button--big Onboarding-footer--marginRight js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('builder-onboarding.skip')%></span>
</button>
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-next">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('builder-onboarding.next')%></span>
</button>
</div>
</div>
<div class="BuilderOnboarding-footer is-step4">
<div class="BuilderOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('builder-onboarding.edit-map')%></span>
</button>
</div>
</div>
</div>
</div>
<div class="BuilderOnboarding-pad3"></div>
<div class="BuilderOnboarding-pad4"></div>
<div class="BuilderOnboarding-pad5"></div>
<div class="BuilderOnboarding-shadow"></div>
@@ -0,0 +1,31 @@
var BuilderOnboardingView = require('./builder-view');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var BUILDER_KEY = 'onboarding';
var REQUIRED_OPTS = [
'onboardings',
'userModel',
'onboardingNotification',
'editorModel'
];
module.exports = (function () {
return {
init: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
},
launch: function () {
if (!this._onboardingNotification.getKey(BUILDER_KEY)) {
this._onboardings.create(function () {
return new BuilderOnboardingView({
userModel: this._userModel,
editorModel: this._editorModel,
onboardingNotification: this._onboardingNotification
});
}.bind(this));
}
}
};
})();
@@ -0,0 +1,51 @@
var _ = require('underscore');
var GenericOnboardingLauncher = function (launcherOpts, viewOpts) {
var _view;
var _onboardingNotification;
var _notificationKey;
var _onboardings;
var _viewOpts;
if (!launcherOpts || !launcherOpts.view) {
throw new Error('view is required');
}
if (!launcherOpts.onboardingNotification) {
throw new Error('onboardingNotification is required');
}
if (!launcherOpts.notificationKey) {
throw new Error('notificationKey is required');
}
if (!launcherOpts.onboardings) {
throw new Error('onboardings is required');
}
if (!viewOpts) {
throw new Error('viewOpts is required');
}
_view = launcherOpts.view;
_onboardingNotification = launcherOpts.onboardingNotification;
_notificationKey = launcherOpts.notificationKey;
_onboardings = launcherOpts.onboardings;
_viewOpts = viewOpts;
return {
launch: function (launchOpts) {
if (!_onboardingNotification.getKey(_notificationKey)) {
_onboardings.create(function () {
var extendedViewOptions = _.extend(_viewOpts, {
onboardingNotification: _onboardingNotification,
notificationKey: _notificationKey
});
return new _view(_.extend(extendedViewOptions, launchOpts));
});
}
}
};
};
module.exports = GenericOnboardingLauncher;
@@ -0,0 +1,220 @@
var $ = require('jquery');
var Backbone = require('backbone');
var _ = require('underscore');
var CoreView = require('backbone/core-view');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var REQUIRED_OPTS = [
'onboardingNotification',
'editorModel',
'template',
'numberOfSteps',
'selector',
'modifier',
'notificationKey'
];
var LEFT_KEY_CODE = 37;
var RIGHT_KEY_CODE = 39;
module.exports = CoreView.extend({
className: 'is-step0 is-opening',
events: {
'click .js-start': '_onClickNext',
'click .js-next': '_onClickNext',
'click .js-close': '_close',
'click .js-highlight': '_close'
},
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
this.$el.addClass(this._selector);
this.model = new Backbone.Model({
step: -1
});
this._defaultBodyPos = {
top: 32,
left: 380
};
this._keyDown = this._onKeyDown.bind(this);
this._initBinds();
},
render: function () {
this.$el.addClass(this._selector + this._modifier);
this.$el.html(this._template());
if (this.model.get('step') === -1) {
this._next();
}
return this;
},
_initBinds: function () {
this.listenTo(this.model, 'destroy', this._close);
this.listenTo(this.model, 'change:step', this._onChangeStep);
this.listenTo(this._editorModel, 'change:edition', this._changeEdition);
$(document).on('keydown', this._keyDown);
},
_changeEdition: function (mdl) {
var isEditing = !!mdl.get('edition');
this.$el.toggleClass('is-editing', isEditing);
},
_prev: function () {
if (this._currentStep() >= 1) {
this.model.set('step', this._currentStep() - 1);
}
},
_next: function () {
if (this._currentStep() < this._numberOfSteps) {
this.model.set('step', this._currentStep() + 1);
}
},
_currentStep: function () {
return this.model.get('step');
},
_onClickNext: function (event) {
if (event) event.stopPropagation();
this._next();
},
_onChangeStep: function () {
var prev = this.model.previous('step');
var step = this.model.get('step');
this.$el.removeClass('is-step' + prev, function () {
this.$el.addClass('is-step' + step);
}.bind(this));
this.$('.js-step').removeClass('is-step' + prev).addClass('is-step' + step);
this.$('.' + this._selector + '-body').fadeOut(0).delay(200).fadeIn(100);
this.$('.' + this._selector + '-step.is-step' + prev).css('display', 'none');
this.$('.' + this._selector + '-footer.is-step' + prev).css('display', 'none');
this.$('.' + this._selector + '-step.is-step' + step).css('display', 'block');
this.$('.' + this._selector + '-footer.is-step' + step).css('display', 'block');
this.$('.' + this._selector + '-contentBody').css('display', step === 0 ? 'block' : 'none');
},
_close: function () {
this._forget();
this.trigger('close', this);
},
_onKeyDown: function (event) {
event.stopPropagation();
if (event.which === LEFT_KEY_CODE) {
this._prev();
} else if (event.which === RIGHT_KEY_CODE) {
this._next();
}
},
_forget: function () {
this._onboardingNotification.setKey(this._notificationKey, true);
this._onboardingNotification.save();
},
clean: function () {
$(document).off('keydown', this._keyDown);
CoreView.prototype.clean.apply(this);
},
_setMiddlePad: function (position, padding, body) {
var $window = $(window);
var $top = this.$('.' + this._selector + '-pads--left .' + this._selector + '-padTop');
var $middle = this.$('.' + this._selector + '-pads--left .' + this._selector + '-padMiddle');
var $bottom = this.$('.' + this._selector + '-pads--left .' + this._selector + '-padBottom');
var vh = $window.height();
var vw = $window.width();
var isSelector = _.isString(position);
var $el = $(position);
var width = 0;
var height = 0;
var left = 0;
var top = 0;
if ($el.length === 0) return;
if (isSelector) {
width = $el.outerWidth();
height = $el.outerHeight();
left = $el.offset().left;
top = $el.offset().top;
} else {
width = position.width;
height = position.height;
left = position.left;
top = position.top;
}
// Apply padding
var appliedPadding = this._buildPadding(padding);
top -= appliedPadding.top;
left -= appliedPadding.left;
width += appliedPadding.left + appliedPadding.right;
height += appliedPadding.top + appliedPadding.bottom;
// Is it place outside the viewport?
if (vw - left > 0 && vw - left < width) {
width = vw - left;
} else if (vw - left <= 0) {
width = 0;
}
// Left offset
this.$('.' + this._selector + '-toolbarOverlay').outerWidth(left);
// Right panel
this.$('.' + this._selector + '-contentWrapper').outerWidth(vw - (left + width));
// Width
this.$('.' + this._selector + '-pads--left').outerWidth(width);
$top.outerWidth(width);
$middle.outerWidth(width);
$bottom.outerWidth(width);
// Height
var topHeight = top;
var middleHeight = height;
var bottomHeight = vh - (topHeight + middleHeight);
$top.outerHeight(topHeight);
$middle.outerHeight(middleHeight);
$bottom.outerHeight(bottomHeight);
// Body text
this.$('.' + this._selector + '-body').css('top', body && body.top ? body.top : this._defaultBodyPos.top);
this.$('.' + this._selector + '-body').css('left', body && body.left ? body.left : this._defaultBodyPos.left);
},
_buildPadding: function (padding) {
var result = {
top: 0,
right: 0,
bottom: 0,
left: 0
};
if (padding) {
result.top = this._calculatePadding(padding.top);
result.right = this._calculatePadding(padding.right);
result.bottom = this._calculatePadding(padding.bottom);
result.left = this._calculatePadding(padding.left);
}
return result;
},
_calculatePadding: function (padding) {
return (padding && _.isFinite(padding)) ? padding : 0;
}
});
@@ -0,0 +1,36 @@
var _ = require('underscore');
var OnboardingView = require('builder/components/onboardings/generic/generic-onboarding-view');
var AnalysesService = require('builder/editor/layers/layer-content-views/analyses/analyses-service');
var template = require('./analysis-onboarding.tpl');
module.exports = OnboardingView.extend({
events: OnboardingView.extendEvents({
'click .js-add-analysis': '_onAddAnalysisClicked'
}),
initialize: function (opts) {
OnboardingView.prototype.initialize.call(this, _.extend(opts, {
template: template,
numberOfSteps: 0,
modifier: '--analysis'
}));
},
_onAddAnalysisClicked: function () {
this._forget();
this.clean();
AnalysesService.addAnalysis();
},
_onChangeStep: function () {
OnboardingView.prototype._onChangeStep.call(this);
var step = this.model.get('step');
if (step === 0) {
this._setMiddlePad('.js-editorPanel');
}
}
});
@@ -0,0 +1,46 @@
<div class="LayerOnboarding-toolbarOverlay"></div>
<div class="LayerOnboarding-pads LayerOnboarding-pads--left">
<div class="LayerOnboarding-padTop"></div>
<div class="LayerOnboarding-padMiddle js-highlight"></div>
</div>
<div class="LayerOnboarding-contentWrapper LayerOnboarding-contentWrapper--analysis is-step0 js-step">
<div class="LayerOnboarding-contentBody LayerOnboarding-contentBody--analysis is-step0 js-step">
<div class="Onboarding-body">
<p class="CDB-Text LayerOnboarding-headerTitle"><%- _t('analysis-onboarding.title')%></p>
<p class="CDB-Text Onboarding-headerDescription"><%- _t('analysis-onboarding.description')%></p>
<ul class="Onboarding-list">
<li class="Onboarding-listItem">
<p class="CDB-Text LayerOnboarding-description"><%- _t('analysis-onboarding.description-list.item1')%></p>
</li>
<li class="Onboarding-listItem">
<p class="CDB-Text LayerOnboarding-description"><%= _t('analysis-onboarding.description-list.item2')%></p>
</li>
<li class="Onboarding-listItem">
<p class="CDB-Text LayerOnboarding-description"><%- _t('analysis-onboarding.description-list.item3')%></p>
</li>
<li class="Onboarding-listItem">
<p class="CDB-Text LayerOnboarding-description"><%- _t('analysis-onboarding.description-list.item4')%></p>
</li>
</ul>
</div>
<div class="LayerOnboarding-footer">
<div class="LayerOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--secondary CDB-Button--white CDB-Button--big Onboarding-footer--marginRight js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('analysis-onboarding.done')%></span>
</button>
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-add-analysis">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('analysis-onboarding.add-analysis')%></span>
</button>
</div>
</div>
</div>
</div>
@@ -0,0 +1,55 @@
var _ = require('underscore');
var $ = require('jquery');
var OnboardingView = require('builder/components/onboardings/generic/generic-onboarding-view');
var template = require('./data-onboarding.tpl');
module.exports = OnboardingView.extend({
initialize: function (opts) {
OnboardingView.prototype.initialize.call(this, _.extend(opts, {
template: template,
numberOfSteps: 4,
modifier: '--data'
}));
},
_onChangeStep: function () {
OnboardingView.prototype._onChangeStep.call(this);
var step = this.model.get('step');
if (step === 0) {
this._setMiddlePad('.js-editorPanel');
} else if (step === 1) {
this._setMiddlePad('.js-editorPanelHeader', {top: 16, right: 24, left: 24});
} else if (step === 2) {
this._setMiddlePad('.js-editorPanelContent', {top: 8, right: 24, left: 24, bottom: -$('.js-optionsBar').outerHeight()});
} else if (step === 3) {
this._setMiddlePad('.js-optionsBar', null, {top: -190});
} else if (step === 4) {
var featurePosition = this._getFeatureEditionPosition();
this._setMiddlePad(featurePosition, {top: 8, right: 8, bottom: 8, left: 8}, {top: -270, left: -330});
}
},
_getFeatureEditionPosition: function () {
var $switch = $('.js-mapTableView').first();
var $featureEdition = $('.js-newGeometryView').first();
var leftOffset = Math.min($switch.length > 0 ? $switch.offset().left : Number.MAX_VALUE, $featureEdition.length > 0 ? $featureEdition.offset().left : Number.MAX_VALUE);
var topOffset = Math.min($switch.length > 0 ? $switch.offset().top : Number.MAX_VALUE, $featureEdition.length > 0 ? $featureEdition.offset().top : Number.MAX_VALUE);
var rightOffset = Math.max(
$switch.length > 0 ? $switch.offset().left + $switch.outerWidth() : Number.MIN_VALUE,
$featureEdition.length > 0 ? $featureEdition.offset().left + $featureEdition.outerWidth() : Number.MIN_VALUE
);
var bottomOffset = Math.max(
$switch.length > 0 ? $switch.offset().top + $switch.outerHeight() : Number.MIN_VALUE,
$featureEdition.length > 0 ? $featureEdition.offset().top + $featureEdition.outerHeight() : Number.MIN_VALUE
);
return {
left: leftOffset,
top: topOffset,
width: rightOffset - leftOffset,
height: bottomOffset - topOffset
};
}
});
@@ -0,0 +1,84 @@
<div class="LayerOnboarding-toolbarOverlay"></div>
<div class="LayerOnboarding-pads LayerOnboarding-pads--left">
<div class="LayerOnboarding-padTop"></div>
<div class="LayerOnboarding-padMiddle js-highlight">
<div class="LayerOnboarding-body is-step0 js-step">
<div class="LayerOnboarding-step is-step1">
<p class="CDB-Text LayerOnboarding-headerTitle">1/4</p>
<p class="CDB-Text LayerOnboarding-headerText"><%- _t('data-onboarding.layer-options.title')%></p>
<p class="CDB-Text LayerOnboarding-description">
<%- _t('data-onboarding.layer-options.description')%>
</p>
</div>
<div class="LayerOnboarding-step is-step2">
<p class="CDB-Text LayerOnboarding-headerTitle">2/4</p>
<p class="CDB-Text LayerOnboarding-headerText"><%- _t('data-onboarding.data-tab.title')%></p>
<p class="CDB-Text LayerOnboarding-description">
<%- _t('data-onboarding.data-tab.description')%>
</p>
</div>
<div class="LayerOnboarding-step is-step3">
<p class="CDB-Text LayerOnboarding-headerTitle">3/4</p>
<p class="CDB-Text LayerOnboarding-headerText"><%- _t('data-onboarding.sql-editor.title')%></p>
<p class="CDB-Text LayerOnboarding-description">
<%- _t('data-onboarding.sql-editor.description')%>
</p>
</div>
<div class="LayerOnboarding-step is-step4">
<p class="CDB-Text LayerOnboarding-headerTitle">4/4</p>
<p class="CDB-Text LayerOnboarding-headerText is-step4"><%- _t('data-onboarding.add-geometry.title')%></p>
<p class="CDB-Text LayerOnboarding-description is-step4">
<%- _t('data-onboarding.add-geometry.description')%>
</p>
</div>
<div class="LayerOnboarding-footer is-step1 is-step2 is-step3">
<div class="LayerOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--secondary CDB-Button--white CDB-Button--big Onboarding-footer--marginRight js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('data-onboarding.exit')%></span>
</button>
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-next">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('data-onboarding.next')%></span>
</button>
</div>
</div>
<div class="LayerOnboarding-footer is-step4">
<div class="LayerOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('data-onboarding.add-geometry.edit-layer') %></span>
</button>
</div>
</div>
</div>
</div>
<div class="LayerOnboarding-padBottom"></div>
</div>
<div class="LayerOnboarding-contentWrapper is-step0 js-step">
<div class="LayerOnboarding-contentBody is-step0 js-step">
<div class="LayerOnboarding-header is-step0">
<p class="CDB-Text LayerOnboarding-headerTitle"><%- _t('data-onboarding.title')%></p>
<p class="CDB-Text LayerOnboarding-description">
<%= _t('data-onboarding.description')%>
</p>
</div>
<div class="LayerOnboarding-footer is-step0">
<div class="LayerOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--secondary CDB-Button--white CDB-Button--big Onboarding-footer--marginRight js-start">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('data-onboarding.take-tour')%></span>
</button>
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('data-onboarding.edit-layer')%></span>
</button>
</div>
</div>
</div>
</div>
@@ -0,0 +1,113 @@
var _ = require('underscore');
var $ = require('jquery');
var OnboardingView = require('builder/components/onboardings/generic/generic-onboarding-view');
var defaultTemplate = require('./style-onboarding.tpl');
var pointsTemplate = require('./style-points-onboarding.tpl');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var REQUIRED_OPTS = [
'geom'
];
module.exports = OnboardingView.extend({
module: 'components/onboardings/layers/style-onboarding/style-onboarding-view',
initialize: function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
var template = defaultTemplate;
var modifier = '--style';
var steps = 2;
if (this._geom === 'point') {
template = pointsTemplate;
steps = 3;
}
OnboardingView.prototype.initialize.call(this, _.extend(opts, {
template: template,
numberOfSteps: steps,
modifier: modifier
}));
},
_onChangeStep: function () {
OnboardingView.prototype._onChangeStep.call(this);
var step = this.model.get('step');
switch (step) {
case 0:
this._setMiddlePad('.js-editorPanel');
break;
case 1:
this._setStepOne();
break;
case 2:
this._setStepTwo();
break;
case 3:
this._highlightOptionsBar();
break;
}
},
_setStepOne: function () {
var $noGeom = $('.js-styleNoGeom');
if ($noGeom.length > 0) {
this._setMiddlePad('.js-styleNoGeom', {top: 8, right: 24, left: 24, bottom: 8});
} else if (this._numberOfSteps === 3) {
var aggregationInfo = this._getAggregationPositionAndPadding();
this._setMiddlePad(aggregationInfo.position, aggregationInfo.padding);
} else {
this._highlightStyleProperties();
}
},
_setStepTwo: function () {
if (this._numberOfSteps === 2) {
this._highlightOptionsBar();
} else {
this._highlightStyleProperties();
}
},
_highlightStyleProperties: function () {
this._setMiddlePad('.js-styleProperties', {top: 8, right: 24, left: 24, bottom: 8});
},
_highlightOptionsBar: function () {
this._setMiddlePad('.js-optionsBar', null, {top: -190});
},
_getAggregationPositionAndPadding: function () {
var $aggregationTypes = $('.js-aggregationTypes');
var $aggregationOptions = $('.js-aggregationOptions');
var left = $aggregationTypes.offset().left;
var top = $aggregationTypes.offset().top;
var width = $aggregationTypes.outerWidth();
var height = $aggregationTypes.outerHeight();
var bottomPadding = 0;
if ($aggregationOptions.length > 0) {
height += $aggregationOptions.outerHeight();
bottomPadding = 8;
}
return {
position: {
top: top,
left: left,
width: width,
height: height
},
padding: {
top: 8,
right: 24,
left: 24,
bottom: bottomPadding
}
};
}
});
@@ -0,0 +1,69 @@
<div class="LayerOnboarding-toolbarOverlay"></div>
<div class="LayerOnboarding-pads LayerOnboarding-pads--left">
<div class="LayerOnboarding-padTop"></div>
<div class="LayerOnboarding-padMiddle js-highlight">
<div class="LayerOnboarding-body is-step0 js-step">
<div class="LayerOnboarding-step is-step1">
<p class="CDB-Text LayerOnboarding-headerTitle">1/2</p>
<p class="CDB-Text LayerOnboarding-headerText"><%- _t('style-onboarding.style.title')%></p>
<p class="CDB-Text LayerOnboarding-description LayerOnboarding-description--style">
<%- _t('style-onboarding.style.short-description')%>
</p>
</div>
<div class="LayerOnboarding-step is-step2">
<p class="CDB-Text LayerOnboarding-headerTitle">2/2</p>
<p class="CDB-Text LayerOnboarding-headerText"><%- _t('style-onboarding.cartocss.title')%></p>
<p class="CDB-Text LayerOnboarding-description">
<%- _t('style-onboarding.cartocss.description')%>
</p>
</div>
<div class="LayerOnboarding-footer is-step1">
<div class="LayerOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--secondary CDB-Button--white CDB-Button--big Onboarding-footer--marginRight js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('style-onboarding.exit')%></span>
</button>
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-next">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('style-onboarding.next')%></span>
</button>
</div>
</div>
<div class="LayerOnboarding-footer is-step2">
<div class="LayerOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('style-onboarding.style-layer')%></span>
</button>
</div>
</div>
</div>
</div>
<div class="LayerOnboarding-padBottom"></div>
</div>
<div class="LayerOnboarding-contentWrapper is-step0 js-step">
<div class="LayerOnboarding-contentBody is-step0 js-step">
<div class="LayerOnboarding-header is-step0">
<p class="CDB-Text LayerOnboarding-headerTitle"><%- _t('style-onboarding.title')%></p>
<p class="CDB-Text LayerOnboarding-description">
<%- _t('style-onboarding.description')%>
</p>
</div>
<div class="LayerOnboarding-footer is-step0">
<div class="LayerOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--secondary CDB-Button--white CDB-Button--big Onboarding-footer--marginRight js-start">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('style-onboarding.take-tour')%></span>
</button>
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('style-onboarding.style-layer')%></span>
</button>
</div>
</div>
</div>
</div>
@@ -0,0 +1,76 @@
<div class="LayerOnboarding-toolbarOverlay"></div>
<div class="LayerOnboarding-pads LayerOnboarding-pads--left">
<div class="LayerOnboarding-padTop"></div>
<div class="LayerOnboarding-padMiddle js-highlight">
<div class="LayerOnboarding-body is-step0 js-step">
<div class="LayerOnboarding-step is-step1">
<p class="CDB-Text LayerOnboarding-headerTitle">1/3</p>
<p class="CDB-Text LayerOnboarding-headerText"><%- _t('style-onboarding.aggregation.title')%></p>
<p class="CDB-Text LayerOnboarding-description">
<%- _t('style-onboarding.aggregation.description')%>
</p>
</div>
<div class="LayerOnboarding-step is-step2">
<p class="CDB-Text LayerOnboarding-headerTitle">2/3</p>
<p class="CDB-Text LayerOnboarding-headerText"><%- _t('style-onboarding.style.title')%></p>
<p class="CDB-Text LayerOnboarding-description LayerOnboarding-description--style">
<%- _t('style-onboarding.style.description')%>
</p>
</div>
<div class="LayerOnboarding-step is-step3">
<p class="CDB-Text LayerOnboarding-headerTitle">3/3</p>
<p class="CDB-Text LayerOnboarding-headerText"><%- _t('style-onboarding.cartocss.title')%></p>
<p class="CDB-Text LayerOnboarding-description">
<%- _t('style-onboarding.cartocss.description')%>
</p>
</div>
<div class="LayerOnboarding-footer is-step1 is-step2">
<div class="LayerOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--secondary CDB-Button--white CDB-Button--big Onboarding-footer--marginRight js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('style-onboarding.exit')%></span>
</button>
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-next">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('style-onboarding.next')%></span>
</button>
</div>
</div>
<div class="LayerOnboarding-footer is-step3">
<div class="LayerOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('style-onboarding.style-layer')%></span>
</button>
</div>
</div>
</div>
</div>
<div class="LayerOnboarding-padBottom"></div>
</div>
<div class="LayerOnboarding-contentWrapper is-step0 js-step">
<div class="LayerOnboarding-contentBody is-step0 js-step">
<div class="LayerOnboarding-header is-step0">
<p class="CDB-Text LayerOnboarding-headerTitle"><%- _t('style-onboarding.title')%></p>
<p class="CDB-Text LayerOnboarding-description">
<%- _t('style-onboarding.description')%>
</p>
</div>
<div class="LayerOnboarding-footer is-step0">
<div class="LayerOnboarding-footerButtons">
<button class="CDB-Button CDB-Button--secondary CDB-Button--white CDB-Button--big Onboarding-footer--marginRight js-start">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('style-onboarding.take-tour')%></span>
</button>
<button class="CDB-Button CDB-Button--primary CDB-Button--big js-close">
<span class="CDB-Button-Text CDB-Text u-upperCase is-semibold CDB-Size-medium"><%- _t('style-onboarding.style-layer')%></span>
</button>
</div>
</div>
</div>
</div>
@@ -0,0 +1,46 @@
var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
/**
* View model of a onboarding
*/
module.exports = Backbone.Model.extend({
defaults: {
show: true,
createContentView: function () {
return new CoreView();
},
getContentClasses: function () {
return null;
}
},
createContentView: function () {
return this.get('createContentView')(this);
},
getContentClasses: function () {
return this.get('contentClasses');
},
show: function () {
this.set('show', true);
},
hide: function () {
this.set('show', false);
},
isHidden: function () {
return !this.get('show');
},
/**
* @override {Backbone.Model.prototype.destroy}
*/
destroy: function () {
var args = Array.prototype.slice.call(arguments);
this.trigger.apply(this, ['destroy'].concat(args));
}
});
@@ -0,0 +1,78 @@
var _ = require('underscore');
var CoreView = require('backbone/core-view');
var template = require('./onboarding.tpl');
// Ought to match the duration of the .Dialog.is-closing animation.
var CLOSE_DELAY_MS = 120;
module.exports = CoreView.extend({
className: 'Onboarding is-opening',
initialize: function () {
this.listenTo(this.model, 'change:show', this._onShowChange);
this.listenTo(this.model, 'destroy', this._onDestroy);
},
render: function () {
this.clearSubViews();
this.$el.html(template());
var view = this.model.createContentView();
this.$el.addClass(this.model.getContentClasses());
this.addView(view);
view.bind('customEvent', this._onCustomEvent, this);
view.bind('close', this._onClose, this);
view.render();
this.$('.js-content').append(view.el);
return this;
},
show: function () {
this.model.show();
},
hide: function () {
this.model.hide();
},
destroy: function () {
// 'remove' would be a better name ofc, but there is already an internal method with that name in CoreView
this.model.destroy();
},
_onShowChange: function (m, show) {
if (show) {
this.$el.show();
this.$el.removeClass('is-closing').addClass('is-opening');
} else {
this.$el.removeClass('is-opening').addClass('is-closing');
this._delayDueToAnimation(function () {
this.$el.hide();
});
}
},
_onClose: function () {
this.destroy();
},
_onCustomEvent: function (customEventName) {
this.destroy();
this.trigger('customEvent', customEventName, this);
},
_onDestroy: function () {
this.hide();
_.invoke(this._subviews, 'allOff');
this._delayDueToAnimation(function () {
this.clean();
});
},
_delayDueToAnimation: function (fn) {
setTimeout(fn.bind(this), CLOSE_DELAY_MS);
}
});
@@ -0,0 +1 @@
<div class="Onboarding js-content"></div>
@@ -0,0 +1,123 @@
var _ = require('underscore');
var Backbone = require('backbone');
var OnboardingView = require('./onboarding-view');
var OnboardingViewModel = require('./onboarding-view-model');
var DESTROYED_ONBOARDING_EVENT = 'destroyedOnboarding';
/**
* Top-level API to handle onboardings.
* Is intended to be instantiated and registered in some top-level namespace to be accessibel within the lifecycle of
* an client-side application.
*
* Example:
* // In some entry-point:
* cdb.onboardings = new OnboardingsServiceModel();
*
* // Later, in any view, calling create will create a new onboarding viewModel
* var onboardingView = cdb.onboardings.create(fn)
*
* You will probably see the name of "Onboarding" here and there, it's the old nomenclature for the concept of Onboarding.
*/
module.exports = Backbone.Model.extend({
/**
* Creates a new onboarding view
*
* @param {Function} createContentView
* @return {View} the new onboarding view
*/
create: function (createContentView, contentClasses) {
if (!_.isFunction(createContentView)) throw new Error('createContentView is required');
if (!this._onboardingView) {
this.trigger('willCreateOnboarding');
this._onboardingView = this._newOnboardingView();
this.trigger('didCreateOnboarding', this._onboardingView);
document.body.appendChild(this._onboardingView.el);
}
this._onboardingView.model.set('createContentView', createContentView);
this._onboardingView.model.set('contentClasses', contentClasses);
this._onboardingView.render();
return this._onboardingView;
},
/**
* Convenience method to add a listener when current onboarding is destroyed
*
* This is the same as doing
* onboardings.create(function (model) {
* model.once('destroy', callback, context); // <-- same as onboardings.onDestroyOnce(callback, context);
* return new MyView({ … });
* });
*
* @param {Function} callback
* @param {Object} [context = undefined]
*/
onDestroyOnce: function (callback, context) {
this.once(DESTROYED_ONBOARDING_EVENT, callback, context);
},
destroy: function () {
if (this._onboardingView) {
this._onboardingView.model.destroy();
}
},
_newOnboardingView: function () {
var viewModel = new OnboardingViewModel();
this._handleBodyClass(viewModel);
this._destroyOnEsc(viewModel);
this.listenToOnce(viewModel, 'destroy', function () {
this._onboardingView = null;
this.trigger.apply(this, [DESTROYED_ONBOARDING_EVENT].concat(Array.prototype.slice.call(arguments)));
this.stopListening(viewModel);
});
var onboardingView = new OnboardingView({
model: viewModel
});
onboardingView.bind('customEvent', function (eventName) {
this.trigger(eventName);
}, this);
return onboardingView;
},
_destroyOnEsc: function (viewModel) {
var destroyOnEsc = function (ev) {
if (ev.keyCode === 27) {
viewModel.destroy();
}
};
document.addEventListener('keydown', destroyOnEsc);
this.listenToOnce(viewModel, 'destroy', function () {
document.removeEventListener('keydown', destroyOnEsc);
});
},
/**
* TL;DR this method manages document.body class state, to enable scroll inside of an open onboarding.
*
* Some onboarding content have too much content that can be displayed in the viewport the scroll needs to be enabled.
* Since the onboarding is implemented as a fixed positioned element the body needs to be fixated too, for the scroll to
* be enabled inside the onboarding instead.
*/
_handleBodyClass: function (viewModel) {
var bodyClass = 'is-inDialog';
document.body.classList.add(bodyClass);
this.listenTo(viewModel, 'change:show', function (m, show) {
document.body.classList[show ? 'add' : 'remove'](bodyClass);
});
this.listenToOnce(viewModel, 'destroy', function () {
document.body.classList.remove(bodyClass);
});
}
});