CartoDB/cartodb20

View on GitHub
lib/assets/javascripts/dashboard/views/public-profile/feed-view.js

Summary

Maintainability
F
3 days
Test Coverage
var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
var moment = require('moment');

var Utils = require('builder/helpers/utils');
var checkAndBuildOpts = require('builder/helpers/required-opts');

var randomQuote = require('builder/components/loading/random-quote');
var Visualizations = require('./user-feed/feed-collection');
var ViewFactory = require('builder/components/view-factory');
var MapCardPreview = require('dashboard/components/mapcard-preview-view');

var feedTemplate = require('./user-feed/feed.tpl');
var mapTemplate = require('./user-feed/map-item.tpl');
var datasetTemplate = require('./user-feed/dataset-item.tpl');
var loaderTemplatePath = require('./user-feed/loading.tpl');
var emptyTemplatePath = require('./user-feed/empty.tpl');
var errorTemplatePath = require('./user-feed/error.tpl');

var REQUIRED_OPTS = [
  'config',
  'authenticatedUser'
];

module.exports = CoreView.extend({
  tagName: 'div',

  _PAGE: 1,
  _ITEMS_PER_PAGE: 8,

  _SMALL_WIDTH: 544,

  _CARD_HEIGHT: 170,
  _LOADER_TITLE: 'Loading visualizations',

  events: {
    'click .js-more': '_onClickMore'
  },

  initialize: function (options) {
    checkAndBuildOpts(options, REQUIRED_OPTS, this);

    _.bindAll(this, '_onFetchError', '_onWindowResize', '_renderStaticMaps');

    this.maps = [];

    this._initModels();
    this._initBindings();
  },

  render: function () {
    this.$el.html(feedTemplate());
    this._renderLoader();
    this._fetchItems({ page: this._PAGE });

    return this;
  },

  _onWindowResize: function () {
    var width = $(window).width();

    if (width <= this._SMALL_WIDTH) {
      this.model.set('size', 'small');
    } else {
      this.model.set('size', 'big');
    }

    this._renderStaticMaps();
  },

  _initModels: function () {
    var size = 'big';
    var wWidth = $(window).width();

    if (wWidth <= this._SMALL_WIDTH) {
      size = 'small';
    }

    this.model = new Backbone.Model({
      vis_count: 0,
      type: '',
      size: size,
      page: 0,
      order_by: 'updated_at'
    });

    this.collection = new Visualizations([], {
      config: this._config
    });
    this.collection.on('reset', this._renderVisualizations, this);
  },

  _initBindings: function () {
    this.model.on('change:show_more', this._onChangeShowMore, this);
    this.model.on('change:show_loader', this._onChangeShowLoader, this);
    this.model.on('change:show_mast', this._onChangeShowMast, this);
    this.model.on('change:vis_count', this._onChangeVisCount, this);

    $(window).on('resize', this._onWindowResize);
  },

  _onChangeVisCount: function () {
    if (this.model.get('vis_count') >= this.collection.total_entries) {
      this.model.set({ show_more: false });
    } else {
      this.model.set({ show_more: true });
    }
  },

  _onChangeShowMast: function () {
    if (this.model.get('show_mast')) {
      this.$('.js-mast').removeClass('is-hidden');
    } else {
      this.$('.js-mast').addClass('is-hidden');
    }
  },

  _onChangeShowLoader: function () {
    if (this.model.get('show_loader')) {
      this.loader.show();
    } else {
      this.loader.hide();
    }
  },

  _onChangeShowMore: function () {
    this.$('.js-more').toggleClass('is-hidden', !this.model.get('show_more'));
  },

  _renderLoader: function () {
    this.loader = ViewFactory.createByTemplate(loaderTemplatePath, {
      title: this._LOADER_TITLE,
      quote: randomQuote()
    });

    this.$el.append(this.loader.render().$el);
  },

  _renderError: function () {
    this.error = ViewFactory.createByTemplate(errorTemplatePath, {
    });

    this.$el.append(this.error.render().$el);
  },

  _renderEmpty: function () {
    this.empty = ViewFactory.createByTemplate(emptyTemplatePath, {
      name: this._config.user_name
    });

    this.$el.append(this.empty.render().$el);
  },

  _getDatasetSize: function (item) {
    var size = item.get('table').size;
    return size ? Utils.readablizeBytes(size, true).split(' ') : 0;
  },

  _getGeometryType: function (geomTypes) {
    if (geomTypes && geomTypes.length > 0) {
      var types = ['point', 'polygon', 'line', 'raster'];
      var geomType = geomTypes[0];

      return _.find(types, function (type) {
        return geomType.toLowerCase().indexOf(type) !== -1;
      });
    }
    return null;
  },

  _renderVisualizations: function () {
    if (this.collection.length === 0) {
      this.model.set({ show_loader: false });
      this._renderEmpty();
      return;
    }

    this.model.set({
      vis_count: this.model.get('vis_count') + this.collection.length,
      show_loader: false,
      show_more: true,
      show_filters: true,
      show_mast: true
    });

    this.collection.each(function (item) {
      var template = item.get('type') === 'derived' ? mapTemplate : datasetTemplate;
      var geomType = (item.get('table') && item.get('table').geometry_types) ? this._getGeometryType(item.get('table').geometry_types) : null;

      var owner = item.get('permission').owner;

      var el = template({
        vis: item.attributes,
        datasetSize: this._getDatasetSize(item),
        username: owner.username,
        avatar_url: owner.avatar_url,
        table_count: owner.table_count,
        maps_count: owner.maps_count,
        geomType: geomType,
        account_host: this._config.get('account_host'),
        base_url: this._config.get('base_url'),
        updated: moment(item.get('updated_at')).fromNow(),
        showLikeButton: this._userLoggedIn()
      });

      this.$('.js-items').append(el);

      var $item = this.$('.js-items').find('[data-vis-id="' + item.get('id') + '"]');

      if (item.get('type') === 'derived') {
        this.maps.push(item);
      }

      if (item.get('type') === 'derived' && !item.get('rendered_' + this.model.get('size'))) {
        this._renderStaticMap(item, $item);
      }
    }, this);
  },

  _renderStaticMaps: function () {
    _.each(this.maps, function (item) {
      if (!item.get('rendered_' + this.model.get('size'))) {
        var $item = this.$('.js-items').find('[data-vis-id="' + item.get('id') + '"]');
        this._renderStaticMap(item, $item);
      }
    }, this);
  },

  _renderStaticMap: function (vis, $el) {
    var visId = vis.get('id');
    var username = vis.get('permission').owner.username;
    var width = 540;
    var className = 'is-' + this.model.get('size');

    if (this.model.get('size') === 'small') {
      width = 288;
    }

    if (visId && username) {
      vis.set('rendered_' + this.model.get('size'), true);

      new MapCardPreview({
        el: $el.find('.js-header'),
        width: width,
        height: this._CARD_HEIGHT,
        mapsApiResource: this._config.getMapsResourceName(username),
        username: username,
        visId: visId,
        className: className,
        config: this._config
      }).load();
    }
  },

  _getLikesEndpoint: function (vis) {
    return '/api/v1/viz/' + vis.get('id') + '/like';
  },

  _userLoggedIn: function () {
    return this._authenticatedUser && !!this._authenticatedUser.get('username');
  },

  _fetchLike: function (model, url) {
    if (this._authenticatedUser.get('username')) {
      // no more loadModelCompleted event
      model.once('change', function () {
        model.set('likeable', true);
      });
      model.url = url;
      model.sync = Backbone.withCORS;
      model.fetch();
    }
  },

  _fetchItems: function (params) {
    var data = _.extend({
      types: 'table,derived',
      privacy: 'public',
      only_published: 'true',
      exclude_shared: 'true',
      per_page: this._ITEMS_PER_PAGE,
      order: 'updated_at'
    }, params);

    this.collection.fetch({
      data: data,
      error: this._onFetchError,
      reset: true
    });
  },

  _onFetchError: function () {
    this.model.set({ show_loader: false });
    this._renderError();
  },

  _onClickMore: function (e) {
    this.killEvent(e);
    this.model.set({ show_more: false, show_loader: true });
    this._fetchItems({ page: ++this._PAGE });
  }
});