From 4e85339bc0ba54331897f8902f1bd45dff13fd9c 2014-01-16 10:57:16 From: Jonathan Frederic Date: 2014-01-16 10:57:16 Subject: [PATCH] add locks to update everywhere by using options to pass this (and check for this) --- diff --git a/IPython/html/static/notebook/js/widgets/widget_bool.js b/IPython/html/static/notebook/js/widgets/widget_bool.js index 4bac72d..5601bfc 100644 --- a/IPython/html/static/notebook/js/widgets/widget_bool.js +++ b/IPython/html/static/notebook/js/widgets/widget_bool.js @@ -33,13 +33,11 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ this.$checkbox = $('') .attr('type', 'checkbox') .click(function(el) { - that.user_invoked_update = true; // Calling model.set will trigger all of the other views of the // model to update. - that.model.set('value', that.$checkbox.prop('checked')); + that.model.set('value', that.$checkbox.prop('checked'), {updated_view: this}); that.touch(); - that.user_invoked_update = false; }) .appendTo(this.$el); @@ -47,12 +45,12 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ this.update(); // Set defaults. }, - update : function(){ + update : function(options){ // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. - if (!this.user_invoked_update) { + if (options === undefined || options.updated_view != this) { this.$checkbox.prop('checked', this.model.get('value')); var disabled = this.model.get('disabled'); @@ -89,12 +87,12 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ this.update(); // Set defaults. }, - update : function(){ + update : function(options){ // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. - if (!this.user_invoked_update) { + if (options === undefined || options.updated_view != this) { if (this.model.get('value')) { this.$button.addClass('active'); } else { @@ -118,13 +116,11 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ // Handles and validates user input. handleClick: function(e) { - this.user_invoked_update = true; - + // Calling model.set will trigger all of the other views of the // model to update. - this.model.set('value', ! $(e.target).hasClass('active')); + this.model.set('value', ! $(e.target).hasClass('active'), {updated_view: this}); this.touch(); - this.user_invoked_update = false; }, }); diff --git a/IPython/html/static/notebook/js/widgets/widget_float_range.js b/IPython/html/static/notebook/js/widgets/widget_float_range.js index c24fa31..10110eb 100644 --- a/IPython/html/static/notebook/js/widgets/widget_float_range.js +++ b/IPython/html/static/notebook/js/widgets/widget_float_range.js @@ -44,66 +44,68 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ this.update(); }, - update : function(){ + update : function(options){ // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. - + + if (options === undefined || options.updated_view != this) { // Slider related keys. - var _keys = ['step', 'max', 'min', 'disabled']; - for (var index in _keys) { - var key = _keys[index]; - if (this.model.get(key) !== undefined) { - this.$slider.slider("option", key, this.model.get(key)); + var _keys = ['step', 'max', 'min', 'disabled']; + for (var index in _keys) { + var key = _keys[index]; + if (this.model.get(key) !== undefined) { + this.$slider.slider("option", key, this.model.get(key)); + } } - } - // WORKAROUND FOR JQUERY SLIDER BUG. - // The horizontal position of the slider handle - // depends on the value of the slider at the time - // of orientation change. Before applying the new - // workaround, we set the value to the minimum to - // make sure that the horizontal placement of the - // handle in the vertical slider is always - // consistent. - var orientation = this.model.get('orientation'); - var value = this.model.get('min'); - this.$slider.slider('option', 'value', value); - this.$slider.slider('option', 'orientation', orientation); - value = this.model.get('value'); - this.$slider.slider('option', 'value', value); + // WORKAROUND FOR JQUERY SLIDER BUG. + // The horizontal position of the slider handle + // depends on the value of the slider at the time + // of orientation change. Before applying the new + // workaround, we set the value to the minimum to + // make sure that the horizontal placement of the + // handle in the vertical slider is always + // consistent. + var orientation = this.model.get('orientation'); + var value = this.model.get('min'); + this.$slider.slider('option', 'value', value); + this.$slider.slider('option', 'orientation', orientation); + value = this.model.get('value'); + this.$slider.slider('option', 'value', value); - // Use the right CSS classes for vertical & horizontal sliders - if (orientation=='vertical') { - this.$slider_container - .removeClass('widget-hslider') - .addClass('widget-vslider'); - this.$el - .removeClass('widget-hbox-single') - .addClass('widget-vbox-single'); - this.$label - .removeClass('widget-hlabel') - .addClass('widget-vlabel'); + // Use the right CSS classes for vertical & horizontal sliders + if (orientation=='vertical') { + this.$slider_container + .removeClass('widget-hslider') + .addClass('widget-vslider'); + this.$el + .removeClass('widget-hbox-single') + .addClass('widget-vbox-single'); + this.$label + .removeClass('widget-hlabel') + .addClass('widget-vlabel'); - } else { - this.$slider_container - .removeClass('widget-vslider') - .addClass('widget-hslider'); - this.$el - .removeClass('widget-vbox-single') - .addClass('widget-hbox-single'); - this.$label - .removeClass('widget-vlabel') - .addClass('widget-hlabel'); - } + } else { + this.$slider_container + .removeClass('widget-vslider') + .addClass('widget-hslider'); + this.$el + .removeClass('widget-vbox-single') + .addClass('widget-hbox-single'); + this.$label + .removeClass('widget-vlabel') + .addClass('widget-hlabel'); + } - var description = this.model.get('description'); - if (description.length === 0) { - this.$label.hide(); - } else { - this.$label.html(description); - this.$label.show(); + var description = this.model.get('description'); + if (description.length === 0) { + this.$label.hide(); + } else { + this.$label.html(description); + this.$label.show(); + } } return IPython.DOMWidgetView.prototype.update.call(this); }, @@ -114,7 +116,7 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ // Calling model.set will trigger all of the other views of the // model to update. - this.model.set('value', ui.value); + this.model.set('value', ui.value, {updated_view: this}); this.touch(); }, }); @@ -141,29 +143,31 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ this.update(); // Set defaults. }, - update : function(){ + update : function(options){ // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. - var value = this.model.get('value'); - if (!this.changing && parseFloat(this.$textbox.val()) != value) { - this.$textbox.val(value); - } - - if (this.model.get('disabled')) { - this.$textbox.attr('disabled','disabled'); - } else { - this.$textbox.removeAttr('disabled'); - } + if (options === undefined || options.updated_view != this) { + var value = this.model.get('value'); + if (parseFloat(this.$textbox.val()) != value) { + this.$textbox.val(value); + } + + if (this.model.get('disabled')) { + this.$textbox.attr('disabled','disabled'); + } else { + this.$textbox.removeAttr('disabled'); + } - var description = this.model.get('description'); - if (description.length === 0) { - this.$label.hide(); - } else { - this.$label.html(description); - this.$label.show(); + var description = this.model.get('description'); + if (description.length === 0) { + this.$label.hide(); + } else { + this.$label.html(description); + this.$label.show(); + } } return IPython.DOMWidgetView.prototype.update.call(this); }, @@ -196,13 +200,11 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ // Apply the value if it has changed. if (numericalValue != this.model.get('value')) { - this.changing = true; // Calling model.set will trigger all of the other views of the // model to update. - this.model.set('value', numericalValue); + this.model.set('value', numericalValue, {updated_view: this}); this.touch(); - this.changing = false; } } }, diff --git a/IPython/html/static/notebook/js/widgets/widget_int_range.js b/IPython/html/static/notebook/js/widgets/widget_int_range.js index e207ee8..b53552c 100644 --- a/IPython/html/static/notebook/js/widgets/widget_int_range.js +++ b/IPython/html/static/notebook/js/widgets/widget_int_range.js @@ -44,66 +44,67 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ this.update(); }, - update : function(){ + update : function(options){ // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. - - // Slider related keys. - var _keys = ['step', 'max', 'min', 'disabled']; - for (var index in _keys) { - var key = _keys[index]; - if (this.model.get(key) !== undefined) { - this.$slider.slider("option", key, this.model.get(key)); + if (options === undefined || options.updated_view != this) { + // Slider related keys. + var _keys = ['step', 'max', 'min', 'disabled']; + for (var index in _keys) { + var key = _keys[index]; + if (this.model.get(key) !== undefined) { + this.$slider.slider("option", key, this.model.get(key)); + } } - } - // WORKAROUND FOR JQUERY SLIDER BUG. - // The horizontal position of the slider handle - // depends on the value of the slider at the time - // of orientation change. Before applying the new - // workaround, we set the value to the minimum to - // make sure that the horizontal placement of the - // handle in the vertical slider is always - // consistent. - var orientation = this.model.get('orientation'); - var value = this.model.get('min'); - this.$slider.slider('option', 'value', value); - this.$slider.slider('option', 'orientation', orientation); - value = this.model.get('value'); - this.$slider.slider('option', 'value', value); + // WORKAROUND FOR JQUERY SLIDER BUG. + // The horizontal position of the slider handle + // depends on the value of the slider at the time + // of orientation change. Before applying the new + // workaround, we set the value to the minimum to + // make sure that the horizontal placement of the + // handle in the vertical slider is always + // consistent. + var orientation = this.model.get('orientation'); + var value = this.model.get('min'); + this.$slider.slider('option', 'value', value); + this.$slider.slider('option', 'orientation', orientation); + value = this.model.get('value'); + this.$slider.slider('option', 'value', value); - // Use the right CSS classes for vertical & horizontal sliders - if (orientation=='vertical') { - this.$slider_container - .removeClass('widget-hslider') - .addClass('widget-vslider'); - this.$el - .removeClass('widget-hbox-single') - .addClass('widget-vbox-single'); - this.$label - .removeClass('widget-hlabel') - .addClass('widget-vlabel'); + // Use the right CSS classes for vertical & horizontal sliders + if (orientation=='vertical') { + this.$slider_container + .removeClass('widget-hslider') + .addClass('widget-vslider'); + this.$el + .removeClass('widget-hbox-single') + .addClass('widget-vbox-single'); + this.$label + .removeClass('widget-hlabel') + .addClass('widget-vlabel'); - } else { - this.$slider_container - .removeClass('widget-vslider') - .addClass('widget-hslider'); - this.$el - .removeClass('widget-vbox-single') - .addClass('widget-hbox-single'); - this.$label - .removeClass('widget-vlabel') - .addClass('widget-hlabel'); - } + } else { + this.$slider_container + .removeClass('widget-vslider') + .addClass('widget-hslider'); + this.$el + .removeClass('widget-vbox-single') + .addClass('widget-hbox-single'); + this.$label + .removeClass('widget-vlabel') + .addClass('widget-hlabel'); + } - var description = this.model.get('description'); - if (description.length === 0) { - this.$label.hide(); - } else { - this.$label.html(description); - this.$label.show(); + var description = this.model.get('description'); + if (description.length === 0) { + this.$label.hide(); + } else { + this.$label.html(description); + this.$label.show(); + } } return IPython.DOMWidgetView.prototype.update.call(this); }, @@ -114,7 +115,7 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ // Calling model.set will trigger all of the other views of the // model to update. - this.model.set('value', ~~ui.value); // Double bit-wise not to truncate decimel + this.model.set('value', ~~ui.value, {updated_view: this}); // Double bit-wise not to truncate decimel this.touch(); }, }); @@ -140,29 +141,30 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ this.update(); // Set defaults. }, - update : function(){ + update : function(options){ // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. + if (options === undefined || options.updated_view != this) { + var value = this.model.get('value'); + if (parseInt(this.$textbox.val()) != value) { + this.$textbox.val(value); + } + + if (this.model.get('disabled')) { + this.$textbox.attr('disabled','disabled'); + } else { + this.$textbox.removeAttr('disabled'); + } - var value = this.model.get('value'); - if (!this.changing && parseInt(this.$textbox.val()) != value) { - this.$textbox.val(value); - } - - if (this.model.get('disabled')) { - this.$textbox.attr('disabled','disabled'); - } else { - this.$textbox.removeAttr('disabled'); - } - - var description = this.model.get('description'); - if (description.length === 0) { - this.$label.hide(); - } else { - this.$label.html(description); - this.$label.show(); + var description = this.model.get('description'); + if (description.length === 0) { + this.$label.hide(); + } else { + this.$label.html(description); + this.$label.show(); + } } return IPython.DOMWidgetView.prototype.update.call(this); }, @@ -195,13 +197,11 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ // Apply the value if it has changed. if (numericalValue != this.model.get('value')) { - this.changing = true; // Calling model.set will trigger all of the other views of the // model to update. - this.model.set('value', numericalValue); + this.model.set('value', numericalValue, {updated_view: this}); this.touch(); - this.changing = false; } } }, diff --git a/IPython/html/static/notebook/js/widgets/widget_multicontainer.js b/IPython/html/static/notebook/js/widgets/widget_multicontainer.js index 50d2675..1e2870c 100644 --- a/IPython/html/static/notebook/js/widgets/widget_multicontainer.js +++ b/IPython/html/static/notebook/js/widgets/widget_multicontainer.js @@ -44,38 +44,39 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ }, - update: function() { + update: function(options) { // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. - - // Set tab titles - var titles = this.model.get('_titles'); - for (var page_index in titles) { - - var accordian = this.containers[page_index]; - if (accordian !== undefined) { - accordian - .find('.accordion-heading') - .find('.accordion-toggle') - .html(titles[page_index]); + + if (options === undefined || options.updated_view != this) { + // Set tab titles + var titles = this.model.get('_titles'); + for (var page_index in titles) { + + var accordian = this.containers[page_index]; + if (accordian !== undefined) { + accordian + .find('.accordion-heading') + .find('.accordion-toggle') + .html(titles[page_index]); + } } - } - // Set selected page - var selected_index = this.model.get("selected_index"); - if (0 <= selected_index && selected_index < this.containers.length) { - for (var index in this.containers) { - if (index==selected_index) { - this.containers[index].find('.accordion-body').collapse('show'); - } else { - this.containers[index].find('.accordion-body').collapse('hide'); + // Set selected page + var selected_index = this.model.get("selected_index"); + if (0 <= selected_index && selected_index < this.containers.length) { + for (var index in this.containers) { + if (index==selected_index) { + this.containers[index].find('.accordion-body').collapse('show'); + } else { + this.containers[index].find('.accordion-body').collapse('hide'); + } + } - } } - return IPython.DOMWidgetView.prototype.update.call(this); }, @@ -99,7 +100,7 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ // Calling model.set will trigger all of the other views of the // model to update. - that.model.set("selected_index", index); + that.model.set("selected_index", index, {updated_view: this}); that.touch(); }) .html('Page ' + index) @@ -160,26 +161,26 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ }, this) }, - update: function() { + update: function(options) { // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. - - // Set tab titles - var titles = this.model.get('_titles'); - for (var page_index in titles) { - var tab_text = this.containers[page_index]; - if (tab_text !== undefined) { - tab_text.html(titles[page_index]); + if (options === undefined || options.updated_view != this) { + // Set tab titles + var titles = this.model.get('_titles'); + for (var page_index in titles) { + var tab_text = this.containers[page_index]; + if (tab_text !== undefined) { + tab_text.html(titles[page_index]); + } } - } - var selected_index = this.model.get('selected_index'); - if (0 <= selected_index && selected_index < this.containers.length) { - this.select_page(selected_index); + var selected_index = this.model.get('selected_index'); + if (0 <= selected_index && selected_index < this.containers.length) { + this.select_page(selected_index); + } } - return IPython.DOMWidgetView.prototype.update.call(this); }, @@ -200,7 +201,7 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ // Calling model.set will trigger all of the other views of the // model to update. - that.model.set("selected_index", index); + that.model.set("selected_index", index, {updated_view: this}); that.touch(); that.select_page(index); }); diff --git a/IPython/html/static/notebook/js/widgets/widget_selection.js b/IPython/html/static/notebook/js/widgets/widget_selection.js index 5e8f78e..128ec56 100644 --- a/IPython/html/static/notebook/js/widgets/widget_selection.js +++ b/IPython/html/static/notebook/js/widgets/widget_selection.js @@ -55,49 +55,51 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ this.update(); }, - update : function(){ + update : function(options){ // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. - var selected_item_text = this.model.get('value'); - selected_item_text = selected_item_text.replace(/ /g, ' '); - selected_item_text = selected_item_text.replace(/\n/g, '
\n'); - if (selected_item_text.length === 0) { - this.$droplabel.html(' '); - } else { - this.$droplabel.html(selected_item_text); - } - - var items = this.model.get('values'); - this.$droplist.html(''); - for (var index in items) { - var that = this; - var item_button = $('') - .html(items[index]) - .on('click', $.proxy(this.handle_click, this)); - this.$droplist.append($('
  • ').append(item_button)); - } - - if (this.model.get('disabled')) { - this.$buttongroup.attr('disabled','disabled'); - this.$droplabel.attr('disabled','disabled'); - this.$dropbutton.attr('disabled','disabled'); - this.$droplist.attr('disabled','disabled'); - } else { - this.$buttongroup.removeAttr('disabled'); - this.$droplabel.removeAttr('disabled'); - this.$dropbutton.removeAttr('disabled'); - this.$droplist.removeAttr('disabled'); - } + if (options === undefined || options.updated_view != this) { + var selected_item_text = this.model.get('value'); + selected_item_text = selected_item_text.replace(/ /g, ' '); + selected_item_text = selected_item_text.replace(/\n/g, '
    \n'); + if (selected_item_text.length === 0) { + this.$droplabel.html(' '); + } else { + this.$droplabel.html(selected_item_text); + } + + var items = this.model.get('values'); + this.$droplist.html(''); + for (var index in items) { + var that = this; + var item_button = $('
    ') + .html(items[index]) + .on('click', $.proxy(this.handle_click, this)); + this.$droplist.append($('
  • ').append(item_button)); + } + + if (this.model.get('disabled')) { + this.$buttongroup.attr('disabled','disabled'); + this.$droplabel.attr('disabled','disabled'); + this.$dropbutton.attr('disabled','disabled'); + this.$droplist.attr('disabled','disabled'); + } else { + this.$buttongroup.removeAttr('disabled'); + this.$droplabel.removeAttr('disabled'); + this.$dropbutton.removeAttr('disabled'); + this.$droplist.removeAttr('disabled'); + } - var description = this.model.get('description'); - if (description.length === 0) { - this.$label.hide(); - } else { - this.$label.html(description); - this.$label.show(); + var description = this.model.get('description'); + if (description.length === 0) { + this.$label.hide(); + } else { + this.$label.html(description); + this.$label.show(); + } } return IPython.DOMWidgetView.prototype.update.call(this); }, @@ -107,7 +109,7 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ // Calling model.set will trigger all of the other views of the // model to update. - this.model.set('value', $(e.target).html(), this); + this.model.set('value', $(e.target).html(), {updated_view: this}); this.touch(); }, @@ -134,62 +136,63 @@ define(["notebook/js/widgets/widget"], function(widget_manager){ this.update(); }, - update : function(){ + update : function(options){ // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. - - // Add missing items to the DOM. - var items = this.model.get('values'); - var disabled = this.model.get('disabled'); - for (var index in items) { - var item_query = ' :input[value="' + items[index] + '"]'; - if (this.$el.find(item_query).length === 0) { - var $label = $('