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