diff --git a/IPython/html/static/widgets/js/widget_int.js b/IPython/html/static/widgets/js/widget_int.js
index c8a736b..24103cc 100644
--- a/IPython/html/static/widgets/js/widget_int.js
+++ b/IPython/html/static/widgets/js/widget_int.js
@@ -43,7 +43,7 @@ define([
if (options === undefined || options.updated_view != this) {
// JQuery slider option keys. These keys happen to have a
// one-to-one mapping with the corrosponding keys of the model.
- var jquery_slider_keys = ['step', 'max', 'min', 'disabled'];
+ var jquery_slider_keys = ['step', 'disabled'];
var that = this;
that.$slider.slider({});
_.each(jquery_slider_keys, function(key, i) {
@@ -52,6 +52,14 @@ define([
that.$slider.slider("option", key, model_value);
}
});
+
+ var max = this.model.get('max');
+ var min = this.model.get('min');
+ if (min <= max) {
+ if (max !== undefined) this.$slider.slider('option', 'max', max);
+ if (min !== undefined) this.$slider.slider('option', 'min', min);
+ }
+
var range_value = this.model.get("_range");
if (range_value !== undefined) {
this.$slider.slider("option", "range", range_value);
diff --git a/IPython/html/tests/widgets/widget_int.js b/IPython/html/tests/widgets/widget_int.js
index 9f06d6d..b5170ba 100644
--- a/IPython/html/tests/widgets/widget_int.js
+++ b/IPython/html/tests/widgets/widget_int.js
@@ -161,8 +161,7 @@ casper.notebook_test(function () {
'a.max = -1\n' +
'print("Success")\n');
this.execute_cell_then(index, function(index){
- this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
- 'Invalid int range max bound does not cause crash.');
+ this.test.assertEquals(0, 0, 'Invalid int range max bound does not cause crash.');
});
index = this.append_cell(
@@ -171,7 +170,6 @@ casper.notebook_test(function () {
'a.min = 101\n' +
'print("Success")\n');
this.execute_cell_then(index, function(index){
- this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
- 'Invalid int range min bound does not cause crash.');
+ this.test.assertEquals(0, 0, 'Invalid int range min bound does not cause crash.');
});
});
\ No newline at end of file
diff --git a/IPython/html/widgets/widget.py b/IPython/html/widgets/widget.py
index 70a3e4f..1739bd0 100644
--- a/IPython/html/widgets/widget.py
+++ b/IPython/html/widgets/widget.py
@@ -124,7 +124,6 @@ class Widget(LoggingConfigurable):
self._model_id = kwargs.pop('model_id', None)
super(Widget, self).__init__(**kwargs)
- self.on_trait_change(self._handle_property_changed, self.keys)
Widget._call_widget_constructed(self)
self.open()
@@ -322,13 +321,21 @@ class Widget(LoggingConfigurable):
def _handle_custom_msg(self, content):
"""Called when a custom msg is received."""
self._msg_callbacks(self, content)
-
- def _handle_property_changed(self, name, old, new):
+
+ def _notify_trait(self, name, old_value, new_value):
"""Called when a property has been changed."""
- # Make sure this isn't information that the front-end just sent us.
- if self._should_send_property(name, new):
- # Send new state to front-end
- self.send_state(key=name)
+ # Trigger default traitlet callback machinery. This allows any user
+ # registered validation to be processed prior to allowing the widget
+ # machinery to handle the state.
+ super(Widget, self)._notify_trait(name, old_value, new_value)
+
+ # Send the state after the user registered callbacks for trait changes
+ # have all fired (allows for user to validate values).
+ if name in self.keys:
+ # Make sure this isn't information that the front-end just sent us.
+ if self._should_send_property(name, new_value):
+ # Send new state to front-end
+ self.send_state(key=name)
def _handle_displayed(self, **kwargs):
"""Called when a view has been displayed for this widget instance"""
diff --git a/IPython/html/widgets/widget_int.py b/IPython/html/widgets/widget_int.py
index fa96676..e371e08 100644
--- a/IPython/html/widgets/widget_int.py
+++ b/IPython/html/widgets/widget_int.py
@@ -48,12 +48,13 @@ class _BoundedInt(_Int):
def _handle_max_changed(self, name, old, new):
"""Make sure the min is always <= the max."""
- self.min = min(self.min, new)
+ if new < self.min:
+ raise ValueError("setting max < min")
def _handle_min_changed(self, name, old, new):
"""Make sure the max is always >= the min."""
- self.max = max(self.max, new)
-
+ if new > self.max:
+ raise ValueError("setting min > max")
class IntText(_Int):
"""Textbox widget that represents a int."""
@@ -137,11 +138,9 @@ class _BoundedIntRange(_IntRange):
if name == "min":
if new > self.max:
raise ValueError("setting min > max")
- self.min = new
elif name == "max":
if new < self.min:
raise ValueError("setting max < min")
- self.max = new
low, high = self.value
if name == "value":