CartoDB/cartodb20

View on GitHub
lib/assets/javascripts/builder/components/onboardings/generic/generic-onboarding-view.js

Summary

Maintainability
C
1 day
Test Coverage
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;
  }
});