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

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;
});