Vizzuality/gfw-climate

View on GitHub
app/assets/javascripts/services/PlaceService.js

Summary

Maintainability
D
2 days
Test Coverage
/**
 * The PlaceService class manages places in the application.
 *
 * A place is just the current state of the application which can be
 * represented as an Object or a URL. For example, the place associated with:
 *
 *   http://localhost:5000/map/6/2/17/ALL/terrain/loss
 *
 * Can also be represented like this:
 *
 *  zoom - 6
 *  lat - 2
 *  lng - 17
 *  iso - ALL
 *  maptype - terrain
 *  baselayers - loss
 *
 * The PlaceService class handles the following use cases:
 *
 * 1) New route updates views
 *
 *   The Router receives a new URL and all application views need to be updated
 *   with the state encoded in the URL.
 *
 *   Here the router publishes the "Place/update" event passing in the route
 *   name and route parameters. The PlaceService handles the event by
 *   standardizing the route parameters and publishing them in a "Place/go"
 *   event. Any presenters listening to the event receives the updated
 *   application state and can update their views.
 *
 * 2) Updated view updates URL
 *
 *   A View state changes (e.g., a new map zoom) and the URL needs to be
 *   updated, not only with its new state, but from the state of all views in
 *   the application that provide state for URLs.
 *
 *   Here presenters publishe the "Place/register" event passing in a
 *   reference to themselves. The PlaceService subscribes to the
 *   "Place/register" event so that it can keep references to all presenters
 *   that provide state. Then the view publishes the "Place/update" event
 *   passing in a "go" parameter. If "go" is false, the PlaceService will
 *   update the URL. Otherwise it will publish the "Place/go" event which will
 *   notify all subscribed presenters.
 *
 * @return {PlaceService} The PlaceService class
 */
define(
  ['underscore', 'mps', 'uri', 'compare/presenters/PresenterClass'],
  function(_, mps, UriTemplate, PresenterClass) {
    'use strict';

    var urlDefaultsParams = {};

    var PlaceService = PresenterClass.extend({
      // _uriTemplate: {
      //   show: '{name}{/iso}{/area}{?display,widgets}',
      //   compare: '{name}{/country1}{/country2}{/country3}{?threshold,widgets}'
      // },

      _uriTemplate:
        '{name}{/country1}{/country2}{/country3}{?threshold,widgets}',

      /**
       * Create new PlaceService with supplied Backbone.Router.
       *
       * @param  {Backbond.Router} router Instance of Backbone.Router
       */
      init: function(router) {
        this.router = router;
        this._presenters = [];
        this._name = null;
        this._super();
      },

      /**
       * Subscribe to application events.
       */
      _subscriptions: [
        {
          'Place/register': function(presenter) {
            this._presenters = _.union(this._presenters, [presenter]);
          }
        },
        {
          'Place/update': function() {
            this._updatePlace();
          }
        }
      ],

      /**
       * Init by the router to set the name
       * and publish the first place.
       *
       * @param  {String} name   Place name
       * @param  {Object} params Url params
       */
      initPlace: function(name, params) {
        this._name = name;
        this._newPlace(params);
      },

      /**
       * Silently updates the url from the presenter params.
       */
      _updatePlace: function() {
        var route, params;
        params = this._destandardizeParams(
          this._getPresenterParams(this._presenters)
        );

        route = this._getRoute(params);
        this.router.navigate(route, { silent: true });
      },

      /**
       * Handles a new place.
       *
       * @param  {Object}  params The place parameters
       */
      _newPlace: function(params) {
        var place = {};

        place.params = this._standardizeParams(params);
        mps.publish('Place/go', [place]);
      },

      /**
       * Return route URL for supplied route name and route params.
       *
       * @param  {Object} params The route params
       * @return {string} The route URL
       */
      _getRoute: function(param) {
        var url = new UriTemplate(this._uriTemplate).fillFromObject(param);
        return decodeURIComponent(url);
      },

      /**
       * Return standardized representation of supplied params object.
       *
       * @param  {Object} params The params to standardize
       * @return {Object} The standardized params.
       */
      _standardizeParams: function(params) {
        var p = _.extendNonNull({}, urlDefaultsParams, params);
        p.name = this._name ? this._name : null;

        // We have to develop this with our params
        p.country1 = p.country1 ? p.country1.toString() : null;
        p.country2 = p.country2 ? p.country2.toString() : null;
        p.country3 = p.country3 ? p.country3.toString() : null;

        return p;
      },

      /**
       * Return formated URL representation of supplied params object based on
       * a route name.
       *
       * @param  {Object} params Place to standardize
       * @return {Object} Params ready for URL
       */
      _destandardizeParams: function(params) {
        var p = _.extendNonNull({}, urlDefaultsParams, params);
        p.name = this._name ? this._name : null;

        // We have to develop this with our params
        p.country1 = p.country1 ? p.country1.toString() : null;
        p.country2 = p.country2 ? p.country2.toString() : null;
        p.country3 = p.country3 ? p.country3.toString() : null;

        return p;
      },

      /**
       * Return param object representing state from all registered presenters
       * that implement getPlaceParams().
       *
       * @param  {Array} presenters The registered presenters
       * @return {Object} Params representing state from all presenters
       */
      _getPresenterParams: function(presenters) {
        var p = {};

        _.each(
          presenters,
          function(presenter) {
            _.extend(p, presenter.getPlaceParams());
          },
          this
        );

        return p;
      }
    });

    return PlaceService;
  }
);