Source: src/js/views/filters/NumericFilterView.js

/*global define */
define(['jquery', 'underscore', 'backbone',
        'models/filters/NumericFilter',
        'views/filters/FilterView',
        'text!templates/filters/numericFilter.html'],
  function($, _, Backbone, NumericFilter, FilterView, Template) {
  'use strict';

  /**
  * @class NumericFilterView
  * @classdesc Render a view of a single NumericFilter model
  * @classcategory Views/Filters
  * @extends FilterView
  */
  var NumericFilterView = FilterView.extend(
    /** @lends NumericFilterView.prototype */{

    /**
    *  A NumericFilter model to be rendered in this view
    * @type {NumericFilter} */
    model: null,

    className: "filter numeric",

    template: _.template(Template),

    events: {
      "change input.range" : "updateRange",
      "change input.single-number" : "updateModel",
      "click .btn"   : "handleChange",
      // "keypress input.single-number" : "handleTyping"
    },
    
    /**    
     * For single input (non-range) models, whether or not to show the search
     * button    
     * @type {boolean}
     */     
    showButton: true,

    initialize: function (options) {
      
      const view = this

      if( !options || typeof options != "object" ){
        var options = {};
      }

      this.model = options.model || new NumericFilter();
      
      if(typeof options.showButton === "boolean"){
        this.showButton = options.showButton;
      }

      // Re-render if the rangeMin, rangeMax, or step changes
      const limitChange = "change:rangeMin change:rangeMax change:step"
      this.stopListening(this.model, limitChange);
      this.listenTo(this.model, limitChange, function () {
        setTimeout(function () {
          view.render();
        }, 1);
      });


    },

    render: function () {
      
      var templateVars = _.extend(
        this.model.toJSON(),
        { showButton: this.showButton }
      );
      
      this.$el.html(
        this.template(templateVars)
      );

      //If a range of values is allowed, show the filter as a numeric slider
      if(
        this.model.get("range") &&
        ( this.model.get("rangeMin") || this.model.get("rangeMax") )
      ){

        var view = this;

        //jQueryUI slider
        this.$('.slider').slider({
            range: true,
            disabled: false,
            min: this.model.get("rangeMin"),  //sets the minimum on the UI slider on initialization
            max: this.model.get("rangeMax"),   //sets the maximum on the UI slider on initialization
            values: [this.model.get("min"), this.model.get("max")], //where the left and right slider handles are
            step: this.model.get("step"),
            stop: function( event, ui ) {

              // When the slider is changed, update the input values
              view.$('input.min').val(ui.values[0]);
              view.$('input.max').val(ui.values[1]);

              //Also update the DateFilter model
              view.model.set('min', ui.values[0]);
              view.model.set('max', ui.values[1]);

            }
          });

          //When the rangeReset event is triggered, reset the slider
          this.listenTo(view.model, "rangeReset", this.resetSlider);

      }
      else {
        // If a range of values is not allowed, show the filter as a single number input
        var numberInput = this.$("input.single-number");
        
        if(numberInput && numberInput.length){
          //If a minimum number is set on the model defaults
          if(this.model.get("min") != null){
            //Set the minimum value on the number input
            numberInput.attr("value", this.model.get("min"));
            this.singleValueType = "min"
          //If a maximum number is set on the model defaults
          } else if(this.model.get("max") != null){
            //Set the minimum value on the number input
            numberInput.attr("value", this.model.get("max"));
            this.singleValueType = "max"
          } else if (this.model.get("values")) {
            if(this.model.get("values").length){
              numberInput.attr("value", this.model.get("values")[0]);
              this.singleValueType = "value"
            }
          }
      }
        //Set a step attribute if there is one set on the model
        if( this.model.get("step") != null ){
          numberInput.attr("step", this.model.get("step"));
        }
      }
    },

    /**
    * Updates the value set on the Filter Model associated with this view.
    * The filter value is grabbed from the input element in this view,
    * and then set on either the min, max, or value attribute, depending
    * on the single value type.
    */
    updateModel: function(){
      // Get the value of the number input
      var value = this.$("input.single-number").val(),
          value = Number(value);
          
      if(["min", "max"].includes(this.singleValueType)){
        this.model.set(this.singleValueType, value)
      } else {
        this.model.set("values", [value])
      }
    },

    /**
    * Gets the min and max years from the number inputs and updates the DateFilter
    *  model and the year UI slider.
    * @param {Event} e - The event that triggered this callback function
    */
    updateRange : function(e) {

      //Get the min and max values from the number inputs
      var minVal = Number(this.$('input.min').val());
      var maxVal = Number(this.$('input.max').val());

      //Update the DateFilter model to match what is in the text inputs
      this.model.set('min', Number(minVal));
      this.model.set('max', Number(maxVal));

      // Update the UI slider to match the new min and max.
      // Can only update the slider values if the slider has been initialized.
      // There's no slider if there is a min & max on the model, but not maxRange
      // and no minRange.
      if(this.$( ".slider" ).slider("instance")){
        this.$( ".slider" ).slider( "option", "values", [ minVal, maxVal ] );
      }

      //Track this event
      MetacatUI.analytics?.trackEvent("portal search", "filter, Data Year", minVal + " to " + maxVal);

    },

    /**
    * Resets the slider to the default values
    */
    resetSlider: function(){

      //Set the min and max values on the slider widget
      this.$( ".slider" ).slider( "option", "values", [ this.model.get("rangeMin"), this.model.get("rangeMax") ] );

      //Reset the min and max values
      this.$('input.min').val( this.model.get("rangeMin") );
      this.$('input.max').val( this.model.get("rangeMax") );

    }

  });
  return NumericFilterView;
});