Show More
@@ -13,37 +13,28 b' in the IPython notebook front-end.' | |||||
13 | # Imports |
|
13 | # Imports | |
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 | from contextlib import contextmanager |
|
15 | from contextlib import contextmanager | |
16 | import inspect |
|
|||
17 | import types |
|
|||
18 |
|
16 | |||
19 | from IPython.kernel.comm import Comm |
|
17 | from IPython.kernel.comm import Comm | |
20 | from IPython.config import LoggingConfigurable |
|
18 | from IPython.config import LoggingConfigurable | |
21 | from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List |
|
19 | from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple | |
22 | from IPython.utils.py3compat import string_types |
|
20 | from IPython.utils.py3compat import string_types | |
23 |
|
21 | |||
24 | #----------------------------------------------------------------------------- |
|
22 | #----------------------------------------------------------------------------- | |
25 | # Classes |
|
23 | # Classes | |
26 | #----------------------------------------------------------------------------- |
|
24 | #----------------------------------------------------------------------------- | |
27 | class CallbackDispatcher(LoggingConfigurable): |
|
25 | class CallbackDispatcher(LoggingConfigurable): | |
28 | acceptable_nargs = List([], help="""List of integers. |
|
26 | """A structure for registering and running callbacks""" | |
29 | The number of arguments in the callbacks registered must match one of |
|
27 | callbacks = List() | |
30 | the integers in this list. If this list is empty or None, it will be |
|
28 | ||
31 | ignored.""") |
|
29 | def __call__(self, *args, **kwargs): | |
32 |
|
30 | """Call all of the registered callbacks.""" | ||
33 | def __init__(self, *pargs, **kwargs): |
|
|||
34 | """Constructor""" |
|
|||
35 | LoggingConfigurable.__init__(self, *pargs, **kwargs) |
|
|||
36 | self.callbacks = {} |
|
|||
37 |
|
||||
38 | def __call__(self, *pargs, **kwargs): |
|
|||
39 | """Call all of the registered callbacks that have the same number of |
|
|||
40 | positional arguments.""" |
|
|||
41 | nargs = len(pargs) |
|
|||
42 | self._validate_nargs(nargs) |
|
|||
43 | value = None |
|
31 | value = None | |
44 |
|
|
32 | for callback in self.callbacks: | |
45 | for callback in self.callbacks[nargs]: |
|
33 | try: | |
46 |
local_value = callback(* |
|
34 | local_value = callback(*args, **kwargs) | |
|
35 | except Exception as e: | |||
|
36 | self.log.warn("Exception in callback %s: %s", callback, e) | |||
|
37 | else: | |||
47 | value = local_value if local_value is not None else value |
|
38 | value = local_value if local_value is not None else value | |
48 | return value |
|
39 | return value | |
49 |
|
40 | |||
@@ -53,69 +44,37 b' class CallbackDispatcher(LoggingConfigurable):' | |||||
53 | Parameters |
|
44 | Parameters | |
54 | ---------- |
|
45 | ---------- | |
55 | callback: method handle |
|
46 | callback: method handle | |
56 | Method to be registered or unregisted. |
|
47 | Method to be registered or unregistered. | |
57 | remove=False: bool |
|
48 | remove=False: bool | |
58 |
Whether |
|
49 | Whether to unregister the callback.""" | |
59 |
|
50 | |||
60 | # Validate the number of arguments that the callback accepts. |
|
|||
61 | nargs = self._get_nargs(callback) |
|
|||
62 | self._validate_nargs(nargs) |
|
|||
63 |
|
||||
64 | # Get/create the appropriate list of callbacks. |
|
|||
65 | if nargs not in self.callbacks: |
|
|||
66 | self.callbacks[nargs] = [] |
|
|||
67 | callback_list = self.callbacks[nargs] |
|
|||
68 |
|
||||
69 | # (Un)Register the callback. |
|
51 | # (Un)Register the callback. | |
70 |
if remove and callback in callback |
|
52 | if remove and callback in self.callbacks: | |
71 |
callback |
|
53 | self.callbacks.remove(callback) | |
72 |
elif not remove and callback not in callback |
|
54 | elif not remove and callback not in self.callbacks: | |
73 |
callback |
|
55 | self.callbacks.append(callback) | |
74 |
|
||||
75 | def _validate_nargs(self, nargs): |
|
|||
76 | if self.acceptable_nargs is not None and \ |
|
|||
77 | len(self.acceptable_nargs) > 0 and \ |
|
|||
78 | nargs not in self.acceptable_nargs: |
|
|||
79 |
|
||||
80 | raise TypeError('Invalid number of positional arguments. See acceptable_nargs list.') |
|
|||
81 |
|
||||
82 | def _get_nargs(self, callback): |
|
|||
83 | """Gets the number of arguments in a callback""" |
|
|||
84 | if callable(callback): |
|
|||
85 | argspec = inspect.getargspec(callback) |
|
|||
86 | if argspec[0] is None: |
|
|||
87 | nargs = 0 |
|
|||
88 | elif argspec[3] is None: |
|
|||
89 | nargs = len(argspec[0]) # Only count vargs! |
|
|||
90 | else: |
|
|||
91 | nargs = len(argspec[0]) - len(argspec[3]) # Subtract number of defaults. |
|
|||
92 |
|
||||
93 | # Bound methods have an additional 'self' argument |
|
|||
94 | if isinstance(callback, types.MethodType): |
|
|||
95 | nargs -= 1 |
|
|||
96 | return nargs |
|
|||
97 | else: |
|
|||
98 | raise TypeError('Callback must be callable.') |
|
|||
99 |
|
56 | |||
100 |
|
57 | |||
101 | class Widget(LoggingConfigurable): |
|
58 | class Widget(LoggingConfigurable): | |
102 | #------------------------------------------------------------------------- |
|
59 | #------------------------------------------------------------------------- | |
103 | # Class attributes |
|
60 | # Class attributes | |
104 | #------------------------------------------------------------------------- |
|
61 | #------------------------------------------------------------------------- | |
105 | widget_construction_callback = None |
|
62 | _widget_construction_callback = None | |
106 | widgets = {} |
|
63 | widgets = {} | |
107 |
|
64 | |||
|
65 | @staticmethod | |||
108 | def on_widget_constructed(callback): |
|
66 | def on_widget_constructed(callback): | |
109 |
"""Registers a callback to be called when a widget is constructed. |
|
67 | """Registers a callback to be called when a widget is constructed. | |
110 |
|
68 | |||
111 | The callback must have the following signature: |
|
69 | The callback must have the following signature: | |
112 | callback(widget)""" |
|
70 | callback(widget)""" | |
113 | Widget.widget_construction_callback = callback |
|
71 | Widget._widget_construction_callback = callback | |
114 |
|
72 | |||
|
73 | @staticmethod | |||
115 | def _call_widget_constructed(widget): |
|
74 | def _call_widget_constructed(widget): | |
116 |
""" |
|
75 | """Static method, called when a widget is constructed.""" | |
117 | if Widget.widget_construction_callback is not None and callable(Widget.widget_construction_callback): |
|
76 | if Widget._widget_construction_callback is not None and callable(Widget._widget_construction_callback): | |
118 | Widget.widget_construction_callback(widget) |
|
77 | Widget._widget_construction_callback(widget) | |
119 |
|
78 | |||
120 | #------------------------------------------------------------------------- |
|
79 | #------------------------------------------------------------------------- | |
121 | # Traits |
|
80 | # Traits | |
@@ -125,20 +84,23 b' class Widget(LoggingConfigurable):' | |||||
125 | _view_name = Unicode(help="""Default view registered in the front-end |
|
84 | _view_name = Unicode(help="""Default view registered in the front-end | |
126 | to use to represent the widget.""", sync=True) |
|
85 | to use to represent the widget.""", sync=True) | |
127 | _comm = Instance('IPython.kernel.comm.Comm') |
|
86 | _comm = Instance('IPython.kernel.comm.Comm') | |
128 |
|
87 | |||
|
88 | closed = Bool(False) | |||
|
89 | ||||
|
90 | keys = List() | |||
|
91 | def _keys_default(self): | |||
|
92 | return [name for name in self.traits(sync=True)] | |||
|
93 | ||||
|
94 | _property_lock = Tuple((None, None)) | |||
|
95 | ||||
|
96 | _display_callbacks = Instance(CallbackDispatcher, ()) | |||
|
97 | _msg_callbacks = Instance(CallbackDispatcher, ()) | |||
|
98 | ||||
129 | #------------------------------------------------------------------------- |
|
99 | #------------------------------------------------------------------------- | |
130 | # (Con/de)structor |
|
100 | # (Con/de)structor | |
131 |
#------------------------------------------------------------------------- |
|
101 | #------------------------------------------------------------------------- | |
132 | def __init__(self, **kwargs): |
|
102 | def __init__(self, **kwargs): | |
133 | """Public constructor""" |
|
103 | """Public constructor""" | |
134 | self.closed = False |
|
|||
135 |
|
||||
136 | self._property_lock = (None, None) |
|
|||
137 | self._keys = None |
|
|||
138 |
|
||||
139 | self._display_callbacks = CallbackDispatcher(acceptable_nargs=[0]) |
|
|||
140 | self._msg_callbacks = CallbackDispatcher(acceptable_nargs=[1, 2]) |
|
|||
141 |
|
||||
142 | super(Widget, self).__init__(**kwargs) |
|
104 | super(Widget, self).__init__(**kwargs) | |
143 |
|
105 | |||
144 | self.on_trait_change(self._handle_property_changed, self.keys) |
|
106 | self.on_trait_change(self._handle_property_changed, self.keys) | |
@@ -150,16 +112,7 b' class Widget(LoggingConfigurable):' | |||||
150 |
|
112 | |||
151 | #------------------------------------------------------------------------- |
|
113 | #------------------------------------------------------------------------- | |
152 | # Properties |
|
114 | # Properties | |
153 |
#------------------------------------------------------------------------- |
|
115 | #------------------------------------------------------------------------- | |
154 | @property |
|
|||
155 | def keys(self): |
|
|||
156 | """Gets a list of the traitlets that should be synced with the front-end.""" |
|
|||
157 | if self._keys is None: |
|
|||
158 | self._keys = [] |
|
|||
159 | for trait_name in self.trait_names(): |
|
|||
160 | if self.trait_metadata(trait_name, 'sync'): |
|
|||
161 | self._keys.append(trait_name) |
|
|||
162 | return self._keys |
|
|||
163 |
|
116 | |||
164 | @property |
|
117 | @property | |
165 | def comm(self): |
|
118 | def comm(self): | |
@@ -186,15 +139,21 b' class Widget(LoggingConfigurable):' | |||||
186 |
|
139 | |||
187 | #------------------------------------------------------------------------- |
|
140 | #------------------------------------------------------------------------- | |
188 | # Methods |
|
141 | # Methods | |
189 |
#------------------------------------------------------------------------- |
|
142 | #------------------------------------------------------------------------- | |
|
143 | def _close(self): | |||
|
144 | """Private close - cleanup objects, registry entries""" | |||
|
145 | del Widget.widgets[self.model_id] | |||
|
146 | self._comm = None | |||
|
147 | self.closed = True | |||
|
148 | ||||
190 | def close(self): |
|
149 | def close(self): | |
191 |
"""Close method. |
|
150 | """Close method. | |
192 |
|
151 | |||
193 | Closes the widget which closes the underlying comm. |
|
152 | Closes the widget which closes the underlying comm. | |
194 | When the comm is closed, all of the widget views are automatically |
|
153 | When the comm is closed, all of the widget views are automatically | |
195 | removed from the front-end.""" |
|
154 | removed from the front-end.""" | |
196 | if not self.closed: |
|
155 | if not self.closed: | |
197 |
self._comm.close() |
|
156 | self._comm.close() | |
198 | self._close() |
|
157 | self._close() | |
199 |
|
158 | |||
200 | def send_state(self, key=None): |
|
159 | def send_state(self, key=None): | |
@@ -232,14 +191,13 b' class Widget(LoggingConfigurable):' | |||||
232 | self._send({"method": "custom", "content": content}) |
|
191 | self._send({"method": "custom", "content": content}) | |
233 |
|
192 | |||
234 | def on_msg(self, callback, remove=False): |
|
193 | def on_msg(self, callback, remove=False): | |
235 |
"""(Un)Register a custom msg rec |
|
194 | """(Un)Register a custom msg receive callback. | |
236 |
|
195 | |||
237 | Parameters |
|
196 | Parameters | |
238 | ---------- |
|
197 | ---------- | |
239 |
callback: |
|
198 | callback: callable | |
240 | Can have a signature of: |
|
199 | callback will be passed two arguments when a message arrives: | |
241 |
|
|
200 | callback(widget, content) | |
242 | - callback(sender, content) Signature 2 |
|
|||
243 | remove: bool |
|
201 | remove: bool | |
244 | True if the callback should be unregistered.""" |
|
202 | True if the callback should be unregistered.""" | |
245 | self._msg_callbacks.register_callback(callback, remove=remove) |
|
203 | self._msg_callbacks.register_callback(callback, remove=remove) | |
@@ -250,9 +208,9 b' class Widget(LoggingConfigurable):' | |||||
250 | Parameters |
|
208 | Parameters | |
251 | ---------- |
|
209 | ---------- | |
252 | callback: method handler |
|
210 | callback: method handler | |
253 |
|
|
211 | Must have a signature of: | |
254 |
|
|
212 | callback(widget, **kwargs) | |
255 |
|
|
213 | kwargs from display are passed through without modification. | |
256 | remove: bool |
|
214 | remove: bool | |
257 | True if the callback should be unregistered.""" |
|
215 | True if the callback should be unregistered.""" | |
258 | self._display_callbacks.register_callback(callback, remove=remove) |
|
216 | self._display_callbacks.register_callback(callback, remove=remove) | |
@@ -278,12 +236,6 b' class Widget(LoggingConfigurable):' | |||||
278 | return key != self._property_lock[0] or \ |
|
236 | return key != self._property_lock[0] or \ | |
279 | value != self._property_lock[1] |
|
237 | value != self._property_lock[1] | |
280 |
|
238 | |||
281 | def _close(self): |
|
|||
282 | """Unsafe close""" |
|
|||
283 | del Widget.widgets[self.model_id] |
|
|||
284 | self._comm = None |
|
|||
285 | self.closed = True |
|
|||
286 |
|
||||
287 | # Event handlers |
|
239 | # Event handlers | |
288 | def _handle_msg(self, msg): |
|
240 | def _handle_msg(self, msg): | |
289 | """Called when a msg is received from the front-end""" |
|
241 | """Called when a msg is received from the front-end""" | |
@@ -312,8 +264,7 b' class Widget(LoggingConfigurable):' | |||||
312 |
|
264 | |||
313 | def _handle_custom_msg(self, content): |
|
265 | def _handle_custom_msg(self, content): | |
314 | """Called when a custom msg is received.""" |
|
266 | """Called when a custom msg is received.""" | |
315 |
self._msg_callbacks(content) |
|
267 | self._msg_callbacks(self, content) | |
316 | self._msg_callbacks(self, content) # Signature 2 |
|
|||
317 |
|
268 | |||
318 | def _handle_property_changed(self, name, old, new): |
|
269 | def _handle_property_changed(self, name, old, new): | |
319 | """Called when a property has been changed.""" |
|
270 | """Called when a property has been changed.""" | |
@@ -324,7 +275,7 b' class Widget(LoggingConfigurable):' | |||||
324 |
|
275 | |||
325 | def _handle_displayed(self, **kwargs): |
|
276 | def _handle_displayed(self, **kwargs): | |
326 | """Called when a view has been displayed for this widget instance""" |
|
277 | """Called when a view has been displayed for this widget instance""" | |
327 | self._display_callbacks(**kwargs) |
|
278 | self._display_callbacks(self, **kwargs) | |
328 |
|
279 | |||
329 | def _pack_widgets(self, x): |
|
280 | def _pack_widgets(self, x): | |
330 | """Recursively converts all widget instances to model id strings. |
|
281 | """Recursively converts all widget instances to model id strings. | |
@@ -367,7 +318,7 b' class Widget(LoggingConfigurable):' | |||||
367 |
|
318 | |||
368 |
|
319 | |||
369 | class DOMWidget(Widget): |
|
320 | class DOMWidget(Widget): | |
370 |
visible = Bool(True, help="Whether |
|
321 | visible = Bool(True, help="Whether the widget is visible.", sync=True) | |
371 | _css = Dict(sync=True) # Internal CSS property dict |
|
322 | _css = Dict(sync=True) # Internal CSS property dict | |
372 |
|
323 | |||
373 | def get_css(self, key, selector=""): |
|
324 | def get_css(self, key, selector=""): | |
@@ -388,7 +339,7 b' class DOMWidget(Widget):' | |||||
388 | else: |
|
339 | else: | |
389 | return None |
|
340 | return None | |
390 |
|
341 | |||
391 | def set_css(self, *args, **kwargs): |
|
342 | def set_css(self, dict_or_key, value=None, selector=''): | |
392 | """Set one or more CSS properties of the widget. |
|
343 | """Set one or more CSS properties of the widget. | |
393 |
|
344 | |||
394 | This function has two signatures: |
|
345 | This function has two signatures: | |
@@ -401,9 +352,9 b' class DOMWidget(Widget):' | |||||
401 | CSS key/value pairs to apply |
|
352 | CSS key/value pairs to apply | |
402 | key: unicode |
|
353 | key: unicode | |
403 | CSS key |
|
354 | CSS key | |
404 | value |
|
355 | value: | |
405 | CSS value |
|
356 | CSS value | |
406 | selector: unicode (optional) |
|
357 | selector: unicode (optional, kwarg only) | |
407 | JQuery selector to use to apply the CSS key/value. If no selector |
|
358 | JQuery selector to use to apply the CSS key/value. If no selector | |
408 | is provided, an empty selector is used. An empty selector makes the |
|
359 | is provided, an empty selector is used. An empty selector makes the | |
409 | front-end try to apply the css to a default element. The default |
|
360 | front-end try to apply the css to a default element. The default | |
@@ -411,37 +362,19 b' class DOMWidget(Widget):' | |||||
411 | of the view that should be styled with common CSS (see |
|
362 | of the view that should be styled with common CSS (see | |
412 | `$el_to_style` in the Javascript code). |
|
363 | `$el_to_style` in the Javascript code). | |
413 | """ |
|
364 | """ | |
414 | selector = kwargs.get('selector', '') |
|
|||
415 | if not selector in self._css: |
|
365 | if not selector in self._css: | |
416 | self._css[selector] = {} |
|
366 | self._css[selector] = {} | |
417 |
|
367 | my_css = self._css[selector] | ||
418 | # Signature 1: set_css(css_dict, selector='') |
|
368 | ||
419 | if len(args) == 1: |
|
369 | if value is None: | |
420 | if isinstance(args[0], dict): |
|
370 | css_dict = dict_or_key | |
421 | for (key, value) in args[0].items(): |
|
|||
422 | if not (key in self._css[selector] and value == self._css[selector][key]): |
|
|||
423 | self._css[selector][key] = value |
|
|||
424 | self.send_state('_css') |
|
|||
425 | else: |
|
|||
426 | raise Exception('css_dict must be a dict.') |
|
|||
427 |
|
||||
428 | # Signature 2: set_css(key, value, selector='') |
|
|||
429 | elif len(args) == 2 or len(args) == 3: |
|
|||
430 |
|
||||
431 | # Selector can be a positional arg if it's the 3rd value |
|
|||
432 | if len(args) == 3: |
|
|||
433 | selector = args[2] |
|
|||
434 | if selector not in self._css: |
|
|||
435 | self._css[selector] = {} |
|
|||
436 |
|
||||
437 | # Only update the property if it has changed. |
|
|||
438 | key = args[0] |
|
|||
439 | value = args[1] |
|
|||
440 | if not (key in self._css[selector] and value == self._css[selector][key]): |
|
|||
441 | self._css[selector][key] = value |
|
|||
442 | self.send_state('_css') # Send new state to client. |
|
|||
443 | else: |
|
371 | else: | |
444 | raise Exception('set_css only accepts 1-3 arguments') |
|
372 | css_dict = {dict_or_key: value} | |
|
373 | ||||
|
374 | for (key, value) in css_dict.items(): | |||
|
375 | if not (key in my_css and value == my_css[key]): | |||
|
376 | my_css[key] = value | |||
|
377 | self.send_state('_css') | |||
445 |
|
378 | |||
446 | def add_class(self, class_names, selector=""): |
|
379 | def add_class(self, class_names, selector=""): | |
447 | """Add class[es] to a DOM element. |
|
380 | """Add class[es] to a DOM element. |
@@ -30,17 +30,14 b' class ButtonWidget(DOMWidget):' | |||||
30 | def __init__(self, **kwargs): |
|
30 | def __init__(self, **kwargs): | |
31 | """Constructor""" |
|
31 | """Constructor""" | |
32 | super(ButtonWidget, self).__init__(**kwargs) |
|
32 | super(ButtonWidget, self).__init__(**kwargs) | |
33 |
self._click_handlers = CallbackDispatcher( |
|
33 | self._click_handlers = CallbackDispatcher() | |
34 | self.on_msg(self._handle_button_msg) |
|
34 | self.on_msg(self._handle_button_msg) | |
35 |
|
35 | |||
36 | def on_click(self, callback, remove=False): |
|
36 | def on_click(self, callback, remove=False): | |
37 |
"""Register a callback to execute when the button is clicked. |
|
37 | """Register a callback to execute when the button is clicked. | |
38 |
|
38 | |||
39 | The callback can either accept no parameters or one sender parameter: |
|
39 | The callback will be called with one argument, | |
40 | - callback() |
|
40 | the clicked button widget instance. | |
41 | - callback(sender) |
|
|||
42 | If the callback has a sender parameter, the ButtonWidget instance that |
|
|||
43 | called the callback will be passed into the method as the sender. |
|
|||
44 |
|
41 | |||
45 | Parameters |
|
42 | Parameters | |
46 | ---------- |
|
43 | ---------- | |
@@ -48,13 +45,12 b' class ButtonWidget(DOMWidget):' | |||||
48 | Set to true to remove the callback from the list of callbacks.""" |
|
45 | Set to true to remove the callback from the list of callbacks.""" | |
49 | self._click_handlers.register_callback(callback, remove=remove) |
|
46 | self._click_handlers.register_callback(callback, remove=remove) | |
50 |
|
47 | |||
51 | def _handle_button_msg(self, content): |
|
48 | def _handle_button_msg(self, _, content): | |
52 | """Handle a msg from the front-end. |
|
49 | """Handle a msg from the front-end. | |
53 |
|
50 | |||
54 | Parameters |
|
51 | Parameters | |
55 | ---------- |
|
52 | ---------- | |
56 | content: dict |
|
53 | content: dict | |
57 | Content of the msg.""" |
|
54 | Content of the msg.""" | |
58 |
if 'event' |
|
55 | if content.get('event', '') == 'click': | |
59 | self._click_handlers() |
|
|||
60 | self._click_handlers(self) |
|
56 | self._click_handlers(self) |
@@ -26,7 +26,7 b' class _StringWidget(DOMWidget):' | |||||
26 |
|
26 | |||
27 |
|
27 | |||
28 | class HTMLWidget(_StringWidget): |
|
28 | class HTMLWidget(_StringWidget): | |
29 |
_view_name = Unicode('HTMLView', sync=True) |
|
29 | _view_name = Unicode('HTMLView', sync=True) | |
30 |
|
30 | |||
31 |
|
31 | |||
32 | class LatexWidget(_StringWidget): |
|
32 | class LatexWidget(_StringWidget): | |
@@ -45,18 +45,17 b' class TextBoxWidget(_StringWidget):' | |||||
45 |
|
45 | |||
46 | def __init__(self, **kwargs): |
|
46 | def __init__(self, **kwargs): | |
47 | super(TextBoxWidget, self).__init__(**kwargs) |
|
47 | super(TextBoxWidget, self).__init__(**kwargs) | |
48 |
self._submission_callbacks = CallbackDispatcher( |
|
48 | self._submission_callbacks = CallbackDispatcher() | |
49 | self.on_msg(self._handle_string_msg) |
|
49 | self.on_msg(self._handle_string_msg) | |
50 |
|
50 | |||
51 | def _handle_string_msg(self, content): |
|
51 | def _handle_string_msg(self, _, content): | |
52 | """Handle a msg from the front-end. |
|
52 | """Handle a msg from the front-end. | |
53 |
|
53 | |||
54 | Parameters |
|
54 | Parameters | |
55 | ---------- |
|
55 | ---------- | |
56 | content: dict |
|
56 | content: dict | |
57 | Content of the msg.""" |
|
57 | Content of the msg.""" | |
58 |
if 'event' |
|
58 | if content.get('event', '') == 'submit': | |
59 | self._submission_callbacks() |
|
|||
60 | self._submission_callbacks(self) |
|
59 | self._submission_callbacks(self) | |
61 |
|
60 | |||
62 | def on_submit(self, callback, remove=False): |
|
61 | def on_submit(self, callback, remove=False): | |
@@ -65,11 +64,9 b' class TextBoxWidget(_StringWidget):' | |||||
65 | Triggered when the user clicks enter. |
|
64 | Triggered when the user clicks enter. | |
66 |
|
65 | |||
67 | Parameters |
|
66 | Parameters | |
68 | callback: Method handle |
|
67 | ---------- | |
69 | Function to be called when the text has been submitted. Function |
|
68 | callback: callable | |
70 | can have two possible signatures: |
|
69 | Will be called with exactly one argument: the Widget instance | |
71 | callback() |
|
|||
72 | callback(sender) |
|
|||
73 | remove: bool (optional) |
|
70 | remove: bool (optional) | |
74 |
Whether |
|
71 | Whether to unregister the callback""" | |
75 | self._submission_callbacks.register_callback(callback, remove=remove) |
|
72 | self._submission_callbacks.register_callback(callback, remove=remove) |
General Comments 0
You need to be logged in to leave comments.
Login now