##// END OF EJS Templates
Changed on_submit to use custom messages instead of stateful communcation
Jonathan Frederic -
Show More
@@ -1,161 +1,161 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // StringWidget
9 // StringWidget
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 **/
15 **/
16
16
17 define(["notebook/js/widget"], function(widget_manager){
17 define(["notebook/js/widget"], function(widget_manager){
18 var StringWidgetModel = IPython.WidgetModel.extend({});
18 var StringWidgetModel = IPython.WidgetModel.extend({});
19 widget_manager.register_widget_model('StringWidgetModel', StringWidgetModel);
19 widget_manager.register_widget_model('StringWidgetModel', StringWidgetModel);
20
20
21 var LabelView = IPython.WidgetView.extend({
21 var LabelView = IPython.WidgetView.extend({
22
22
23 // Called when view is rendered.
23 // Called when view is rendered.
24 render : function(){
24 render : function(){
25 this.update(); // Set defaults.
25 this.update(); // Set defaults.
26 },
26 },
27
27
28 // Handles: Backend -> Frontend Sync
28 // Handles: Backend -> Frontend Sync
29 // Frontent -> Frontend Sync
29 // Frontent -> Frontend Sync
30 update : function(){
30 update : function(){
31 this.$el.html(this.model.get('value'));
31 this.$el.html(this.model.get('value'));
32 return IPython.WidgetView.prototype.update.call(this);
32 return IPython.WidgetView.prototype.update.call(this);
33 },
33 },
34
34
35 });
35 });
36
36
37 widget_manager.register_widget_view('LabelView', LabelView);
37 widget_manager.register_widget_view('LabelView', LabelView);
38
38
39 var TextAreaView = IPython.WidgetView.extend({
39 var TextAreaView = IPython.WidgetView.extend({
40
40
41 // Called when view is rendered.
41 // Called when view is rendered.
42 render : function(){
42 render : function(){
43 this.$el
43 this.$el
44 .addClass('widget-hbox')
44 .addClass('widget-hbox')
45 .html('');
45 .html('');
46 this.$label = $('<div />')
46 this.$label = $('<div />')
47 .appendTo(this.$el)
47 .appendTo(this.$el)
48 .addClass('widget-hlabel')
48 .addClass('widget-hlabel')
49 .hide();
49 .hide();
50 this.$textbox = $('<textarea />')
50 this.$textbox = $('<textarea />')
51 .attr('rows', 5)
51 .attr('rows', 5)
52 .addClass('widget-text')
52 .addClass('widget-text')
53 .appendTo(this.$el);
53 .appendTo(this.$el);
54 this.$el_to_style = this.$textbox; // Set default element to style
54 this.$el_to_style = this.$textbox; // Set default element to style
55 this.update(); // Set defaults.
55 this.update(); // Set defaults.
56 },
56 },
57
57
58 // Handles: Backend -> Frontend Sync
58 // Handles: Backend -> Frontend Sync
59 // Frontent -> Frontend Sync
59 // Frontent -> Frontend Sync
60 update : function(){
60 update : function(){
61 if (!this.user_invoked_update) {
61 if (!this.user_invoked_update) {
62 this.$textbox.val(this.model.get('value'));
62 this.$textbox.val(this.model.get('value'));
63 }
63 }
64
64
65 if (this.last_scroll_to_bottom == undefined) {
65 if (this.last_scroll_to_bottom == undefined) {
66 this.last_scroll_to_bottom = 0;
66 this.last_scroll_to_bottom = 0;
67 }
67 }
68 if (this.last_scroll_to_bottom < this.model.get('scroll_to_bottoms')) {
68 if (this.last_scroll_to_bottom < this.model.get('scroll_to_bottoms')) {
69 this.last_scroll_to_bottom < this.model.get('scroll_to_bottoms');
69 this.last_scroll_to_bottom < this.model.get('scroll_to_bottoms');
70 this.$textbox.scrollTop(this.$textbox[0].scrollHeight);
70 this.$textbox.scrollTop(this.$textbox[0].scrollHeight);
71 }
71 }
72
72
73 var disabled = this.model.get('disabled');
73 var disabled = this.model.get('disabled');
74 this.$textbox.prop('disabled', disabled);
74 this.$textbox.prop('disabled', disabled);
75
75
76 var description = this.model.get('description');
76 var description = this.model.get('description');
77 if (description.length == 0) {
77 if (description.length == 0) {
78 this.$label.hide();
78 this.$label.hide();
79 } else {
79 } else {
80 this.$label.html(description);
80 this.$label.html(description);
81 this.$label.show();
81 this.$label.show();
82 }
82 }
83 return IPython.WidgetView.prototype.update.call(this);
83 return IPython.WidgetView.prototype.update.call(this);
84 },
84 },
85
85
86 events: {"keyup textarea" : "handleChanging",
86 events: {"keyup textarea" : "handleChanging",
87 "paste textarea" : "handleChanging",
87 "paste textarea" : "handleChanging",
88 "cut textarea" : "handleChanging"},
88 "cut textarea" : "handleChanging"},
89
89
90 // Handles and validates user input.
90 // Handles and validates user input.
91 handleChanging: function(e) {
91 handleChanging: function(e) {
92 this.user_invoked_update = true;
92 this.user_invoked_update = true;
93 this.model.set('value', e.target.value);
93 this.model.set('value', e.target.value);
94 this.model.update_other_views(this);
94 this.model.update_other_views(this);
95 this.user_invoked_update = false;
95 this.user_invoked_update = false;
96 },
96 },
97 });
97 });
98
98
99 widget_manager.register_widget_view('TextAreaView', TextAreaView);
99 widget_manager.register_widget_view('TextAreaView', TextAreaView);
100
100
101 var TextBoxView = IPython.WidgetView.extend({
101 var TextBoxView = IPython.WidgetView.extend({
102
102
103 // Called when view is rendered.
103 // Called when view is rendered.
104 render : function(){
104 render : function(){
105 this.$el
105 this.$el
106 .addClass('widget-hbox-single')
106 .addClass('widget-hbox-single')
107 .html('');
107 .html('');
108 this.$label = $('<div />')
108 this.$label = $('<div />')
109 .addClass('widget-hlabel')
109 .addClass('widget-hlabel')
110 .appendTo(this.$el)
110 .appendTo(this.$el)
111 .hide();
111 .hide();
112 this.$textbox = $('<input type="text" />')
112 this.$textbox = $('<input type="text" />')
113 .addClass('input')
113 .addClass('input')
114 .addClass('widget-text')
114 .addClass('widget-text')
115 .appendTo(this.$el);
115 .appendTo(this.$el);
116 this.$el_to_style = this.$textbox; // Set default element to style
116 this.$el_to_style = this.$textbox; // Set default element to style
117 this.update(); // Set defaults.
117 this.update(); // Set defaults.
118 },
118 },
119
119
120 // Handles: Backend -> Frontend Sync
120 // Handles: Backend -> Frontend Sync
121 // Frontent -> Frontend Sync
121 // Frontent -> Frontend Sync
122 update : function(){
122 update : function(){
123 if (this.$textbox.val() != this.model.get('value')) {
123 if (this.$textbox.val() != this.model.get('value')) {
124 this.$textbox.val(this.model.get('value'));
124 this.$textbox.val(this.model.get('value'));
125 }
125 }
126
126
127 var disabled = this.model.get('disabled');
127 var disabled = this.model.get('disabled');
128 this.$textbox.prop('disabled', disabled);
128 this.$textbox.prop('disabled', disabled);
129
129
130 var description = this.model.get('description');
130 var description = this.model.get('description');
131 if (description.length == 0) {
131 if (description.length == 0) {
132 this.$label.hide();
132 this.$label.hide();
133 } else {
133 } else {
134 this.$label.html(description);
134 this.$label.html(description);
135 this.$label.show();
135 this.$label.show();
136 }
136 }
137 return IPython.WidgetView.prototype.update.call(this);
137 return IPython.WidgetView.prototype.update.call(this);
138 },
138 },
139
139
140 events: {"keyup input" : "handleChanging",
140 events: {"keyup input" : "handleChanging",
141 "paste input" : "handleChanging",
141 "paste input" : "handleChanging",
142 "cut input" : "handleChanging",
142 "cut input" : "handleChanging",
143 "keypress input" : "handleKeypress"},
143 "keypress input" : "handleKeypress"},
144
144
145 // Handles and validates user input.
145 // Handles and validates user input.
146 handleChanging: function(e) {
146 handleChanging: function(e) {
147 this.model.set('value', e.target.value);
147 this.model.set('value', e.target.value);
148 this.model.update_other_views(this);
148 this.model.update_other_views(this);
149 },
149 },
150
150
151 // Handles text submition
151 // Handles text submition
152 handleKeypress: function(e) {
152 handleKeypress: function(e) {
153 if (e.keyCode == 13) { // Return key
153 if (e.keyCode == 13) { // Return key
154 this.model.set('submits', this.model.get('submits') + 1);
154 this.model.last_modified_view = this; // For callbacks.
155 this.model.update_other_views(this);
155 this.model.send({event: 'submit'});
156 }
156 }
157 },
157 },
158 });
158 });
159
159
160 widget_manager.register_widget_view('TextBoxView', TextBoxView);
160 widget_manager.register_widget_view('TextBoxView', TextBoxView);
161 });
161 });
@@ -1,84 +1,112 b''
1 """StringWidget class.
1 """StringWidget class.
2
2
3 Represents a unicode string using a widget.
3 Represents a unicode string using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 import inspect
16 import inspect
17 import types
17 import types
18
18
19 from .widget import Widget
19 from .widget import Widget
20 from IPython.utils.traitlets import Unicode, Bool, List, Int
20 from IPython.utils.traitlets import Unicode, Bool, List, Int
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Classes
23 # Classes
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 class StringWidget(Widget):
25 class StringWidget(Widget):
26 target_name = Unicode('StringWidgetModel')
26 target_name = Unicode('StringWidgetModel')
27 default_view_name = Unicode('TextBoxView')
27 default_view_name = Unicode('TextBoxView')
28
28
29 # Keys
29 # Keys
30 _keys = ['value', 'disabled', 'description', 'submits', 'scroll_to_bottoms']
30 _keys = ['value', 'disabled', 'description', 'scroll_to_bottoms']
31 value = Unicode(help="String value")
31 value = Unicode(help="String value")
32 disabled = Bool(False, help="Enable or disable user changes")
32 disabled = Bool(False, help="Enable or disable user changes")
33 description = Unicode(help="Description of the value this widget represents")
33 description = Unicode(help="Description of the value this widget represents")
34 submits = Int(0, help="Used to capture and fire submission ")
35 scroll_to_bottoms = Int(0, help="Used to scroll a TextAreaView to the bottom")
34 scroll_to_bottoms = Int(0, help="Used to scroll a TextAreaView to the bottom")
36
35
37
36
38 def __init__(self, **kwargs):
37 def __init__(self, **kwargs):
39 super(StringWidget, self).__init__(**kwargs)
38 super(StringWidget, self).__init__(**kwargs)
40 self._submission_callbacks = []
39 self._submission_callbacks = []
40 self.on_msg(self._handle_string_msg)
41
41
42
42
43 def scroll_to_bottom(self):
43 def scroll_to_bottom(self):
44 self.scroll_to_bottoms += 1
44 self.scroll_to_bottoms += 1
45
45
46
46
47 def on_click(self, callback, remove=False):
48 """Register a callback to execute when the button is clicked. The
49 callback can either accept no parameters or one sender parameter:
50 - callback()
51 - callback(sender)
52 If the callback has a sender parameter, the ButtonWidget instance that
53 called the callback will be passed into the method as the sender.
54
55 Parameters
56 ----------
57 remove : bool (optional)
58 Set to true to remove the callback from the list of callbacks."""
59 if remove:
60 self._click_handlers.remove(callback)
61 elif not callback in self._click_handlers:
62 self._click_handlers.append(callback)
63
64
65 def _handle_string_msg(self, content):
66 """Handle a msg from the front-end
67
68 Parameters
69 ----------
70 content: dict
71 Content of the msg."""
72 if 'event' in content and content['event'] == 'submit':
73 self._handle_submit()
74
75
47 def on_submit(self, callback, remove=False):
76 def on_submit(self, callback, remove=False):
48 """Register a callback to handle text submission (triggered when the
77 """Register a callback to handle text submission (triggered when the
49 user clicks enter).
78 user clicks enter).
50
79
51 Parameters
80 Parameters
52 callback: Method handle
81 callback: Method handle
53 Function to be called when the text has been submitted. Function
82 Function to be called when the text has been submitted. Function
54 can have two possible signatures:
83 can have two possible signatures:
55 callback()
84 callback()
56 callback(sender)
85 callback(sender)
57 remove: bool (optional)
86 remove: bool (optional)
58 Whether or not to unregister the callback"""
87 Whether or not to unregister the callback"""
59 if remove and callback in self._submission_callbacks:
88 if remove and callback in self._submission_callbacks:
60 self._submission_callbacks.remove(callback)
89 self._submission_callbacks.remove(callback)
61 elif not remove and not callback in self._submission_callbacks:
90 elif not remove and not callback in self._submission_callbacks:
62 self._submission_callbacks.append(callback)
91 self._submission_callbacks.append(callback)
63
92
64
93
65 def _submits_changed(self, name, old_value, new_value):
94 def _handle_submit(self):
66 """Handles when a string widget view is submitted."""
95 """Handles when a string widget view is submitted."""
67 if new_value > old_value:
96 for handler in self._submission_callbacks:
68 for handler in self._submission_callbacks:
97 if callable(handler):
69 if callable(handler):
98 argspec = inspect.getargspec(handler)
70 argspec = inspect.getargspec(handler)
99 nargs = len(argspec[0])
71 nargs = len(argspec[0])
100
72
101 # Bound methods have an additional 'self' argument
73 # Bound methods have an additional 'self' argument
102 if isinstance(handler, types.MethodType):
74 if isinstance(handler, types.MethodType):
103 nargs -= 1
75 nargs -= 1
104
76
105 # Call the callback
77 # Call the callback
106 if nargs == 0:
78 if nargs == 0:
107 handler()
79 handler()
108 elif nargs == 1:
80 elif nargs == 1:
109 handler(self)
81 handler(self)
110 else:
82 else:
111 raise TypeError('StringWidget submit callback must ' \
83 raise TypeError('StringWidget submit callback must ' \
112 'accept 0 or 1 arguments.')
84 'accept 0 or 1 arguments.')
General Comments 0
You need to be logged in to leave comments. Login now