diff --git a/IPython/html/static/notebook/js/widget.js b/IPython/html/static/notebook/js/widget.js
index d985b68..d6ef81f 100644
--- a/IPython/html/static/notebook/js/widget.js
+++ b/IPython/html/static/notebook/js/widget.js
@@ -36,6 +36,7 @@ define(["components/underscore/underscore-min",
this.msg_throttle = 3;
this.msg_buffer = null;
this.views = {};
+ this._custom_msg_callbacks = [];
// Remember comm associated with the model.
this.comm = comm;
@@ -64,15 +65,17 @@ define(["components/underscore/underscore-min",
}
},
- send: function(content) {
+
+ send: function(content, cell) {
// Used the last modified view as the sender of the message. This
// will insure that any python code triggered by the sent message
// can create and display widgets and output.
- var cell = null;
- if (this.last_modified_view != undefined &&
- this.last_modified_view.cell != undefined) {
- cell = this.last_modified_view.cell;
+ if (cell === undefined) {
+ if (this.last_modified_view != undefined &&
+ this.last_modified_view.cell != undefined) {
+ cell = this.last_modified_view.cell;
+ }
}
var callbacks = this._make_callbacks(cell);
var data = {'custom_content': content};
@@ -90,15 +93,29 @@ define(["components/underscore/underscore-min",
},
- on_msg: function (callback) {
- this._msg_callback = callback;
+ on_msg: function (callback, remove) {
+ if (remove) {
+ var found_index = -1;
+ for (var index in this._custom_msg_callbacks) {
+ if (callback === this._custom_msg_callbacks[index]) {
+ found_index = index;
+ break;
+ }
+ }
+
+ if (found_index >= 0) {
+ this._custom_msg_callbacks.splice(found_index, 1);
+ }
+ } else {
+ this._custom_msg_callbacks.push(callback)
+ }
},
_handle_custom_msg: function (content) {
- if (this._msg_callback) {
+ for (var index in this._custom_msg_callbacks) {
try {
- this._msg_callback(content);
+ this._custom_msg_callbacks[index](content);
} catch (e) {
console.log("Exception in widget model msg callback", e, content);
}
@@ -465,6 +482,11 @@ define(["components/underscore/underscore-min",
elements.removeClass(class_list);
}
},
+
+
+ send: function(content) {
+ this.model.send({event: 'click'}, this.cell);
+ },
update: function() {
if (this.model.get('visible') != undefined) {
diff --git a/IPython/html/static/notebook/js/widgets/button.js b/IPython/html/static/notebook/js/widgets/button.js
index 9e0f452..d450984 100644
--- a/IPython/html/static/notebook/js/widgets/button.js
+++ b/IPython/html/static/notebook/js/widgets/button.js
@@ -50,8 +50,7 @@ define(["notebook/js/widget"], function(widget_manager){
},
_handle_click: function(){
- this.model.last_modified_view = this; // For callbacks.
- this.model.send({event: 'click'});
+ this.send({event: 'click'});
},
});
diff --git a/IPython/html/static/notebook/js/widgets/string.js b/IPython/html/static/notebook/js/widgets/string.js
index 45255bc..a943017 100644
--- a/IPython/html/static/notebook/js/widgets/string.js
+++ b/IPython/html/static/notebook/js/widgets/string.js
@@ -39,7 +39,7 @@ define(["notebook/js/widget"], function(widget_manager){
var TextAreaView = IPython.WidgetView.extend({
// Called when view is rendered.
- render : function(){
+ render: function(){
this.$el
.addClass('widget-hbox')
.html('');
@@ -53,23 +53,30 @@ define(["notebook/js/widget"], function(widget_manager){
.appendTo(this.$el);
this.$el_to_style = this.$textbox; // Set default element to style
this.update(); // Set defaults.
+
+ this.on_msg();
+ },
+
+
+ _handle_textarea_msg: function (content){
+ if (content.method == "scroll_to_bottom") {
+ this.scroll_to_bottom();
+ }
+ },
+
+
+ scroll_to_bottom: function (){
+ this.$textbox.scrollTop(this.$textbox[0].scrollHeight);
},
+
// Handles: Backend -> Frontend Sync
// Frontent -> Frontend Sync
- update : function(){
+ update: function(){
if (!this.user_invoked_update) {
this.$textbox.val(this.model.get('value'));
}
- if (this.last_scroll_to_bottom == undefined) {
- this.last_scroll_to_bottom = 0;
- }
- if (this.last_scroll_to_bottom < this.model.get('scroll_to_bottoms')) {
- this.last_scroll_to_bottom < this.model.get('scroll_to_bottoms');
- this.$textbox.scrollTop(this.$textbox[0].scrollHeight);
- }
-
var disabled = this.model.get('disabled');
this.$textbox.prop('disabled', disabled);
@@ -83,9 +90,9 @@ define(["notebook/js/widget"], function(widget_manager){
return IPython.WidgetView.prototype.update.call(this);
},
- events: {"keyup textarea" : "handleChanging",
- "paste textarea" : "handleChanging",
- "cut textarea" : "handleChanging"},
+ events: {"keyup textarea": "handleChanging",
+ "paste textarea": "handleChanging",
+ "cut textarea": "handleChanging"},
// Handles and validates user input.
handleChanging: function(e) {
@@ -101,7 +108,7 @@ define(["notebook/js/widget"], function(widget_manager){
var TextBoxView = IPython.WidgetView.extend({
// Called when view is rendered.
- render : function(){
+ render: function(){
this.$el
.addClass('widget-hbox-single')
.html('');
@@ -119,7 +126,7 @@ define(["notebook/js/widget"], function(widget_manager){
// Handles: Backend -> Frontend Sync
// Frontent -> Frontend Sync
- update : function(){
+ update: function(){
if (this.$textbox.val() != this.model.get('value')) {
this.$textbox.val(this.model.get('value'));
}
@@ -137,10 +144,10 @@ define(["notebook/js/widget"], function(widget_manager){
return IPython.WidgetView.prototype.update.call(this);
},
- events: {"keyup input" : "handleChanging",
- "paste input" : "handleChanging",
- "cut input" : "handleChanging",
- "keypress input" : "handleKeypress"},
+ events: {"keyup input": "handleChanging",
+ "paste input": "handleChanging",
+ "cut input": "handleChanging",
+ "keypress input": "handleKeypress"},
// Handles and validates user input.
handleChanging: function(e) {
@@ -151,8 +158,7 @@ define(["notebook/js/widget"], function(widget_manager){
// Handles text submition
handleKeypress: function(e) {
if (e.keyCode == 13) { // Return key
- this.model.last_modified_view = this; // For callbacks.
- this.model.send({event: 'submit'});
+ this.send({event: 'submit'});
}
},
});
diff --git a/IPython/html/widgets/widget_string.py b/IPython/html/widgets/widget_string.py
index 89c4d95..7b81715 100644
--- a/IPython/html/widgets/widget_string.py
+++ b/IPython/html/widgets/widget_string.py
@@ -27,11 +27,10 @@ class StringWidget(Widget):
default_view_name = Unicode('TextBoxView')
# Keys
- _keys = ['value', 'disabled', 'description', 'scroll_to_bottoms']
+ _keys = ['value', 'disabled', 'description']
value = Unicode(help="String value")
disabled = Bool(False, help="Enable or disable user changes")
description = Unicode(help="Description of the value this widget represents")
- scroll_to_bottoms = Int(0, help="Used to scroll a TextAreaView to the bottom")
def __init__(self, **kwargs):
@@ -41,7 +40,7 @@ class StringWidget(Widget):
def scroll_to_bottom(self):
- self.scroll_to_bottoms += 1
+ self._comm.send({"method": "scroll_to_bottom"})
def on_click(self, callback, remove=False):