##// END OF EJS Templates
Add scroll_to_bottom method for TextAreaView (StringWidget).
Jonathan Frederic -
Show More
@@ -1,154 +1,162 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.$el = $('<div />');
25 this.$el = $('<div />');
26 this.update(); // Set defaults.
26 this.update(); // Set defaults.
27 },
27 },
28
28
29 // Handles: Backend -> Frontend Sync
29 // Handles: Backend -> Frontend Sync
30 // Frontent -> Frontend Sync
30 // Frontent -> Frontend Sync
31 update : function(){
31 update : function(){
32 this.$el.html(this.model.get('value'));
32 this.$el.html(this.model.get('value'));
33 return IPython.WidgetView.prototype.update.call(this);
33 return IPython.WidgetView.prototype.update.call(this);
34 },
34 },
35
35
36 });
36 });
37
37
38 widget_manager.register_widget_view('LabelView', LabelView);
38 widget_manager.register_widget_view('LabelView', LabelView);
39
39
40 var TextAreaView = IPython.WidgetView.extend({
40 var TextAreaView = IPython.WidgetView.extend({
41
41
42 // Called when view is rendered.
42 // Called when view is rendered.
43 render : function(){
43 render : function(){
44 this.$el
44 this.$el
45 .addClass('widget-hbox')
45 .addClass('widget-hbox')
46 .html('');
46 .html('');
47 this.$label = $('<div />')
47 this.$label = $('<div />')
48 .appendTo(this.$el)
48 .appendTo(this.$el)
49 .addClass('widget-hlabel')
49 .addClass('widget-hlabel')
50 .hide();
50 .hide();
51 this.$textbox = $('<textarea />')
51 this.$textbox = $('<textarea />')
52 .attr('rows', 5)
52 .attr('rows', 5)
53 .addClass('widget-text')
53 .addClass('widget-text')
54 .appendTo(this.$el);
54 .appendTo(this.$el);
55 this.$el_to_style = this.$textbox; // Set default element to style
55 this.$el_to_style = this.$textbox; // Set default element to style
56 this.update(); // Set defaults.
56 this.update(); // Set defaults.
57 },
57 },
58
58
59 // Handles: Backend -> Frontend Sync
59 // Handles: Backend -> Frontend Sync
60 // Frontent -> Frontend Sync
60 // Frontent -> Frontend Sync
61 update : function(){
61 update : function(){
62 if (!this.user_invoked_update) {
62 if (!this.user_invoked_update) {
63 this.$textbox.val(this.model.get('value'));
63 this.$textbox.val(this.model.get('value'));
64 }
64 }
65
65
66 if (this.last_scroll_to_bottom == undefined) {
67 this.last_scroll_to_bottom = 0;
68 }
69 if (this.last_scroll_to_bottom < this.model.get('scroll_to_bottoms')) {
70 this.last_scroll_to_bottom < this.model.get('scroll_to_bottoms');
71 this.$textbox.scrollTop(this.$textbox[0].scrollHeight);
72 }
73
66 var disabled = this.model.get('disabled');
74 var disabled = this.model.get('disabled');
67 this.$textbox.prop('disabled', disabled);
75 this.$textbox.prop('disabled', disabled);
68
76
69 var description = this.model.get('description');
77 var description = this.model.get('description');
70 if (description.length == 0) {
78 if (description.length == 0) {
71 this.$label.hide();
79 this.$label.hide();
72 } else {
80 } else {
73 this.$label.html(description);
81 this.$label.html(description);
74 this.$label.show();
82 this.$label.show();
75 }
83 }
76 return IPython.WidgetView.prototype.update.call(this);
84 return IPython.WidgetView.prototype.update.call(this);
77 },
85 },
78
86
79 events: {"keyup textarea" : "handleChanging",
87 events: {"keyup textarea" : "handleChanging",
80 "paste textarea" : "handleChanging",
88 "paste textarea" : "handleChanging",
81 "cut textarea" : "handleChanging"},
89 "cut textarea" : "handleChanging"},
82
90
83 // Handles and validates user input.
91 // Handles and validates user input.
84 handleChanging: function(e) {
92 handleChanging: function(e) {
85 this.user_invoked_update = true;
93 this.user_invoked_update = true;
86 this.model.set('value', e.target.value);
94 this.model.set('value', e.target.value);
87 this.model.update_other_views(this);
95 this.model.update_other_views(this);
88 this.user_invoked_update = false;
96 this.user_invoked_update = false;
89 },
97 },
90 });
98 });
91
99
92 widget_manager.register_widget_view('TextAreaView', TextAreaView);
100 widget_manager.register_widget_view('TextAreaView', TextAreaView);
93
101
94 var TextBoxView = IPython.WidgetView.extend({
102 var TextBoxView = IPython.WidgetView.extend({
95
103
96 // Called when view is rendered.
104 // Called when view is rendered.
97 render : function(){
105 render : function(){
98 this.$el
106 this.$el
99 .addClass('widget-hbox-single')
107 .addClass('widget-hbox-single')
100 .html('');
108 .html('');
101 this.$label = $('<div />')
109 this.$label = $('<div />')
102 .addClass('widget-hlabel')
110 .addClass('widget-hlabel')
103 .appendTo(this.$el)
111 .appendTo(this.$el)
104 .hide();
112 .hide();
105 this.$textbox = $('<input type="text" />')
113 this.$textbox = $('<input type="text" />')
106 .addClass('input')
114 .addClass('input')
107 .addClass('widget-text')
115 .addClass('widget-text')
108 .appendTo(this.$el);
116 .appendTo(this.$el);
109 this.$el_to_style = this.$textbox; // Set default element to style
117 this.$el_to_style = this.$textbox; // Set default element to style
110 this.update(); // Set defaults.
118 this.update(); // Set defaults.
111 },
119 },
112
120
113 // Handles: Backend -> Frontend Sync
121 // Handles: Backend -> Frontend Sync
114 // Frontent -> Frontend Sync
122 // Frontent -> Frontend Sync
115 update : function(){
123 update : function(){
116 if (this.$textbox.val() != this.model.get('value')) {
124 if (this.$textbox.val() != this.model.get('value')) {
117 this.$textbox.val(this.model.get('value'));
125 this.$textbox.val(this.model.get('value'));
118 }
126 }
119
127
120 var disabled = this.model.get('disabled');
128 var disabled = this.model.get('disabled');
121 this.$textbox.prop('disabled', disabled);
129 this.$textbox.prop('disabled', disabled);
122
130
123 var description = this.model.get('description');
131 var description = this.model.get('description');
124 if (description.length == 0) {
132 if (description.length == 0) {
125 this.$label.hide();
133 this.$label.hide();
126 } else {
134 } else {
127 this.$label.html(description);
135 this.$label.html(description);
128 this.$label.show();
136 this.$label.show();
129 }
137 }
130 return IPython.WidgetView.prototype.update.call(this);
138 return IPython.WidgetView.prototype.update.call(this);
131 },
139 },
132
140
133 events: {"keyup input" : "handleChanging",
141 events: {"keyup input" : "handleChanging",
134 "paste input" : "handleChanging",
142 "paste input" : "handleChanging",
135 "cut input" : "handleChanging",
143 "cut input" : "handleChanging",
136 "keypress input" : "handleKeypress"},
144 "keypress input" : "handleKeypress"},
137
145
138 // Handles and validates user input.
146 // Handles and validates user input.
139 handleChanging: function(e) {
147 handleChanging: function(e) {
140 this.model.set('value', e.target.value);
148 this.model.set('value', e.target.value);
141 this.model.update_other_views(this);
149 this.model.update_other_views(this);
142 },
150 },
143
151
144 // Handles text submition
152 // Handles text submition
145 handleKeypress: function(e) {
153 handleKeypress: function(e) {
146 if (e.keyCode == 13) { // Return key
154 if (e.keyCode == 13) { // Return key
147 this.model.set('submits', this.model.get('submits') + 1);
155 this.model.set('submits', this.model.get('submits') + 1);
148 this.model.update_other_views(this);
156 this.model.update_other_views(this);
149 }
157 }
150 },
158 },
151 });
159 });
152
160
153 widget_manager.register_widget_view('TextBoxView', TextBoxView);
161 widget_manager.register_widget_view('TextBoxView', TextBoxView);
154 });
162 });
@@ -1,79 +1,84 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']
30 _keys = ['value', 'disabled', 'description', 'submits', '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 ")
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")
35
36
36
37
37 def __init__(self, **kwargs):
38 def __init__(self, **kwargs):
38 super(StringWidget, self).__init__(**kwargs)
39 super(StringWidget, self).__init__(**kwargs)
39 self._submission_callbacks = []
40 self._submission_callbacks = []
40
41
41
42
43 def scroll_to_bottom(self):
44 self.scroll_to_bottoms += 1
45
46
42 def on_submit(self, callback, remove=False):
47 def on_submit(self, callback, remove=False):
43 """Register a callback to handle text submission (triggered when the
48 """Register a callback to handle text submission (triggered when the
44 user clicks enter).
49 user clicks enter).
45
50
46 Parameters
51 Parameters
47 callback: Method handle
52 callback: Method handle
48 Function to be called when the text has been submitted. Function
53 Function to be called when the text has been submitted. Function
49 can have two possible signatures:
54 can have two possible signatures:
50 callback()
55 callback()
51 callback(sender)
56 callback(sender)
52 remove: bool (optional)
57 remove: bool (optional)
53 Whether or not to unregister the callback"""
58 Whether or not to unregister the callback"""
54 if remove and callback in self._submission_callbacks:
59 if remove and callback in self._submission_callbacks:
55 self._submission_callbacks.remove(callback)
60 self._submission_callbacks.remove(callback)
56 elif not remove and not callback in self._submission_callbacks:
61 elif not remove and not callback in self._submission_callbacks:
57 self._submission_callbacks.append(callback)
62 self._submission_callbacks.append(callback)
58
63
59
64
60 def _submits_changed(self, name, old_value, new_value):
65 def _submits_changed(self, name, old_value, new_value):
61 """Handles when a string widget view is submitted."""
66 """Handles when a string widget view is submitted."""
62 if new_value > old_value:
67 if new_value > old_value:
63 for handler in self._submission_callbacks:
68 for handler in self._submission_callbacks:
64 if callable(handler):
69 if callable(handler):
65 argspec = inspect.getargspec(handler)
70 argspec = inspect.getargspec(handler)
66 nargs = len(argspec[0])
71 nargs = len(argspec[0])
67
72
68 # Bound methods have an additional 'self' argument
73 # Bound methods have an additional 'self' argument
69 if isinstance(handler, types.MethodType):
74 if isinstance(handler, types.MethodType):
70 nargs -= 1
75 nargs -= 1
71
76
72 # Call the callback
77 # Call the callback
73 if nargs == 0:
78 if nargs == 0:
74 handler()
79 handler()
75 elif nargs == 1:
80 elif nargs == 1:
76 handler(self)
81 handler(self)
77 else:
82 else:
78 raise TypeError('StringWidget submit callback must ' \
83 raise TypeError('StringWidget submit callback must ' \
79 '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