From 71d59e8299998040c5ba3929911dd44d1423ab35 2014-09-24 13:56:01 From: Gordon Ball Date: 2014-09-24 13:56:01 Subject: [PATCH] Add support for parsing pairs of numbers for range sliders --- diff --git a/IPython/html/static/widgets/js/widget_float.js b/IPython/html/static/widgets/js/widget_float.js index 128c135..dec3afd 100644 --- a/IPython/html/static/widgets/js/widget_float.js +++ b/IPython/html/static/widgets/js/widget_float.js @@ -9,9 +9,9 @@ define([ var IntTextView = int_widgets.IntTextView; var FloatSliderView = IntSliderView.extend({ - _validate_text_input: function(x) { - return parseFloat(x); - }, + _parse_text_input: parseFloat, + + _range_regex: /^\s*([+-]?\d*\.?\d+)\s*[-:]\s*([+-]?\d*\.?\d+)/, _validate_slide_value: function(x) { // Validate the value of the slider before sending it to the back-end diff --git a/IPython/html/static/widgets/js/widget_int.js b/IPython/html/static/widgets/js/widget_int.js index 73abd3d..e8f759c 100644 --- a/IPython/html/static/widgets/js/widget_int.js +++ b/IPython/html/static/widgets/js/widget_int.js @@ -170,34 +170,70 @@ define([ }, handleTextChange: function() { + // this handles the entry of text into the contentEditable label + // first, the value is checked if it contains a parseable number + // (or pair of numbers, for the _range case) + // then it is clamped within the min-max range of the slider + // finally, the model is updated if the value is to be changed + // + // if any of these conditions are not met, the text is reset + // + // the step size is not enforced + var text = this.$readout.text(); - var value = this._validate_text_input(text); - if (isNaN(value)) { - this.$readout.text(this.model.get('value')); + var vmin = this.model.get('min'); + var vmax = this.model.get('max'); + if (this.model.get("_range")) { + // range case + // ranges can be expressed either "val-val" or "val:val" (+spaces) + var match = this._range_regex.exec(text); + if (match) { + var values = [this._parse_text_input(match[1]), + this._parse_text_input(match[2])]; + // reject input where NaN or lower > upper + if (isNaN(values[0]) || + isNaN(values[1]) || + (values[0] > values[1])) { + this.$readout.text(this.model.get('value').join('-')); + } else { + // clamp to range + values = [Math.max(Math.min(values[0], vmax), vmin), + Math.max(Math.min(values[1], vmax), vmin)]; + + if ((values[0] != this.model.get('value')[0]) || + (values[1] != this.model.get('value')[1])) { + this.$readout.text(values.join('-')); + this.model.set('value', values, {updated_view: this}); + this.touch(); + } else { + this.$readout.text(this.model.get('value').join('-')); + } + } + } else { + this.$readout.text(this.model.get('value').join('-')); + } } else { - //check for outside range - if (value > this.model.get('max')) value = this.model.get('max'); - if (value < this.model.get('min')) value = this.model.get('min'); - - //update the readout unconditionally - //this covers eg, entering a float value which rounds to the - //existing int value, which will not trigger an update since the model - //doesn't change, but we should update the text to reflect that - //a float value isn't being used - this.$readout.text(value); - - //note that the step size currently isn't enforced, so if an - //off-step value is input it will be retained - - //update the model - this.model.set('value', value, {updated_view: this}); - this.touch(); + // single value case + var value = this._parse_text_input(text); + if (isNaN(value)) { + this.$readout.text(this.model.get('value')); + } else { + value = Math.max(Math.min(value, vmax), vmin); + + if (value != this.model.get('value')) { + this.$readout.text(value); + this.model.set('value', value, {updated_view: this}); + this.touch(); + } else { + this.$readout.text(this.model.get('value')); + } + } } }, - _validate_text_input: function(x) { - return parseInt(x); - }, + _parse_text_input: parseInt, + + _range_regex: /^\s*([+-]?\d+)\s*[-:]\s*([+-]?\d+)/, handleSliderChange: function(e, ui) { // Called when the slider value is changed.