Source: src/js/views/maps/LayerListView.js


'use strict';

define(
  [
    'jquery',
    'underscore',
    'backbone',
    'text!templates/maps/layer-list.html',
    // Sub-views
    'views/maps/LayerItemView'
  ],
  function (
    $,
    _,
    Backbone,
    Template,
    // Sub-views
    LayerItemView
  ) {

    /**
    * @class LayerListView
    * @classdesc A Layer List shows a collection of Map Assets, like imagery and vector
    * layers. Each Map Asset in the collection is rendered as a single item in the list.
    * Each item can be clicked for more details.
    * @classcategory Views/Maps
    * @name LayerListView
    * @extends Backbone.View
    * @screenshot views/maps/LayerListView.png
    * @since 2.18.0
    * @constructs
    */
    var LayerListView = Backbone.View.extend(
      /** @lends LayerListView.prototype */{

        /**
        * The type of View this is
        * @type {string}
        */
        type: 'LayerListView',

        /**
        * The HTML classes to use for this view's element
        * @type {string}
        */
        className: 'layer-list',

        /**
        * The collection of layers to display in the list
        * @type {MapAssets}
        */
        collection: undefined,

        /**
        * Whether the layer list is a under a category. Flat layer list and categorized
        * layer list are styled differently.
        * @type {boolean}
        */
        isCategorized: undefined,

        /**
         * The primary HTML template for this view
         * @type {Underscore.template}
         */
        template: _.template(Template),

        /**
        * The events this view will listen to and the associated function to call.
        * @type {Object}
        */
        events: {
          // 'event selector': 'function',
        },

        /**
        * Executed when a new LayerListView is created
        * @param {Object} [options] - A literal object with options to pass to the view
        */
        initialize: function (options) {

          try {
            // Get all the options and apply them to this view
            if (typeof options == 'object') {
              for (const [key, value] of Object.entries(options)) {
                this[key] = value;
              }
            }
            this.setListeners();
          } catch (e) {
            console.log('A LayerListView failed to initialize. Error message: ' + e);
          }

        },

        /**
         * Remove any event listeners on the collection
         * @since 2.27.0
         */
        removeListeners: function () {
          try {
            if (this.collection) {
              this.stopListening(this.collection);
            }
          } catch (e) {
            console.log('Failed to remove listeners:', e);
          }
        },

        /**
         * Add or remove items from the list when the collection changes
         * @since 2.27.0
         */
        setListeners: function () {
          try {
            if (this.collection) {
              this.listenTo(this.collection, 'add remove reset', this.render);
            }
          } catch (e) {
            console.log('Failed to set listeners:', e);
          }
        },

        /**
        * Renders this view
        * @return {LayerListView} Returns the rendered view element
        */
        render: function () {
          this.$el.html(this.template({}));

          // Ensure the view's main element has the given class name
          this.el.classList.add(this.className);

          if (!this.collection) {
            return;
          }

          // Render a layer item for each layer in the collection
          this.layerItemViews = this.collection.reduce((memo, layerModel) => {
            if (layerModel.get('hideInLayerList') === true){
              // skip this layer
              return memo;
            }
            const layerItem = new LayerItemView({
              model: layerModel,
              isCategorized: this.isCategorized,
            })
            layerItem.render();
            this.el.appendChild(layerItem.el);
            memo.push(layerItem);
            return memo;
          }, []);

          return this;
        },

        /**
         * Searches and only displays layers that match the text.
         * @param {string} [text] - The search text from user input.
         * @returns {boolean} - True if a layer item matches the text
         */
        search(text) {
          return this.layerItemViews.reduce((matched, layerItem) => {
            return layerItem.search(text) || matched;
          }, false);
        },
      }
    );

    return LayerListView;

  }
);