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