##// END OF EJS Templates
Make the widget keys property traverse the superclasses and accumulate the _keys attributes....
Jason Grout -
Show More
@@ -1,457 +1,460 b''
1 """Base Widget class. Allows user to create widgets in the backend that render
1 """Base Widget class. Allows user to create widgets in the backend that render
2 in the IPython notebook frontend.
2 in the IPython notebook frontend.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 from copy import copy
15 from copy import copy
16 from glob import glob
16 from glob import glob
17 import uuid
17 import uuid
18 import sys
18 import sys
19 import os
19 import os
20 import inspect
20 import inspect
21 import types
21 import types
22
22
23 import IPython
23 import IPython
24 from IPython.kernel.comm import Comm
24 from IPython.kernel.comm import Comm
25 from IPython.config import LoggingConfigurable
25 from IPython.config import LoggingConfigurable
26 from IPython.utils.traitlets import Unicode, Dict, List, Instance, Bool
26 from IPython.utils.traitlets import Unicode, Dict, List, Instance, Bool
27 from IPython.display import Javascript, display
27 from IPython.display import Javascript, display
28 from IPython.utils.py3compat import string_types
28 from IPython.utils.py3compat import string_types
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Classes
31 # Classes
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 class BaseWidget(LoggingConfigurable):
34 class BaseWidget(LoggingConfigurable):
35
35
36 # Shared declarations (Class level)
36 # Shared declarations (Class level)
37 _keys = List(Unicode, default_value = [],
37 _keys = List(Unicode, default_value = [],
38 help="List of keys comprising the state of the model.", allow_none=False)
38 help="List of keys comprising the state of the model.", allow_none=False)
39 widget_construction_callback = None
39 widget_construction_callback = None
40
40
41 def on_widget_constructed(callback):
41 def on_widget_constructed(callback):
42 """Class method, registers a callback to be called when a widget is
42 """Class method, registers a callback to be called when a widget is
43 constructed. The callback must have the following signature:
43 constructed. The callback must have the following signature:
44 callback(widget)"""
44 callback(widget)"""
45 BaseWidget.widget_construction_callback = callback
45 BaseWidget.widget_construction_callback = callback
46
46
47 def _handle_widget_constructed(widget):
47 def _handle_widget_constructed(widget):
48 """Class method, called when a widget is constructed."""
48 """Class method, called when a widget is constructed."""
49 if BaseWidget.widget_construction_callback is not None and callable(BaseWidget.widget_construction_callback):
49 if BaseWidget.widget_construction_callback is not None and callable(BaseWidget.widget_construction_callback):
50 BaseWidget.widget_construction_callback(widget)
50 BaseWidget.widget_construction_callback(widget)
51
51
52
52
53
53
54 # Public declarations (Instance level)
54 # Public declarations (Instance level)
55 target_name = Unicode('widget', help="""Name of the backbone model
55 target_name = Unicode('widget', help="""Name of the backbone model
56 registered in the frontend to create and sync this widget with.""")
56 registered in the frontend to create and sync this widget with.""")
57 default_view_name = Unicode(help="""Default view registered in the frontend
57 default_view_name = Unicode(help="""Default view registered in the frontend
58 to use to represent the widget.""")
58 to use to represent the widget.""")
59
59
60 # Private/protected declarations
60 # Private/protected declarations
61 # todo: change this to a context manager
61 # todo: change this to a context manager
62 _property_lock = (None, None) # Last updated (key, value) from the front-end. Prevents echo.
62 _property_lock = (None, None) # Last updated (key, value) from the front-end. Prevents echo.
63 _displayed = False
63 _displayed = False
64 _comm = Instance('IPython.kernel.comm.Comm')
64 _comm = Instance('IPython.kernel.comm.Comm')
65
65
66 def __init__(self, **kwargs):
66 def __init__(self, **kwargs):
67 """Public constructor
67 """Public constructor
68 """
68 """
69 self._display_callbacks = []
69 self._display_callbacks = []
70 self._msg_callbacks = []
70 self._msg_callbacks = []
71 super(BaseWidget, self).__init__(**kwargs)
71 super(BaseWidget, self).__init__(**kwargs)
72
72
73 self.on_trait_change(self._handle_property_changed, self.keys)
73 self.on_trait_change(self._handle_property_changed, self.keys)
74 BaseWidget._handle_widget_constructed(self)
74 BaseWidget._handle_widget_constructed(self)
75
75
76 def __del__(self):
76 def __del__(self):
77 """Object disposal"""
77 """Object disposal"""
78 self.close()
78 self.close()
79
79
80
80
81 def close(self):
81 def close(self):
82 """Close method. Closes the widget which closes the underlying comm.
82 """Close method. Closes the widget which closes the underlying comm.
83 When the comm is closed, all of the widget views are automatically
83 When the comm is closed, all of the widget views are automatically
84 removed from the frontend."""
84 removed from the frontend."""
85 self._close_communication()
85 self._close_communication()
86
86
87
87 _keys = ['default_view_name']
88
88 # Properties
89 # Properties
89 @property
90 @property
90 def keys(self):
91 def keys(self):
91 keys = ['default_view_name']
92 """Lazily accumulate _keys from all superclasses and cache them in this class"""
92 keys.extend(self._keys)
93 keys=[]
94 for c in self.__class__.mro():
95 if hasattr(c, '_keys'):
96 keys.extend(getattr(c,'_keys'))
97 else:
98 break
99 # cache so future lookups are fast
100 self.__class__.x = keys
93 return keys
101 return keys
94
102
95 @property
103 @property
96 def comm(self):
104 def comm(self):
97 if self._comm is None:
105 if self._comm is None:
98 self._open_communication()
106 self._open_communication()
99 return self._comm
107 return self._comm
100
108
101 @property
109 @property
102 def model_id(self):
110 def model_id(self):
103 return self.comm.comm_id
111 return self.comm.comm_id
104
112
105 # Event handlers
113 # Event handlers
106 def _handle_msg(self, msg):
114 def _handle_msg(self, msg):
107 """Called when a msg is recieved from the frontend"""
115 """Called when a msg is recieved from the frontend"""
108 data = msg['content']['data']
116 data = msg['content']['data']
109 method = data['method']
117 method = data['method']
110
118
111 # Handle backbone sync methods CREATE, PATCH, and UPDATE
119 # Handle backbone sync methods CREATE, PATCH, and UPDATE
112 if method == 'backbone':
120 if method == 'backbone':
113 if 'sync_method' in data and 'sync_data' in data:
121 if 'sync_method' in data and 'sync_data' in data:
114 sync_method = data['sync_method']
122 sync_method = data['sync_method']
115 sync_data = data['sync_data']
123 sync_data = data['sync_data']
116 self._handle_recieve_state(sync_data) # handles all methods
124 self._handle_recieve_state(sync_data) # handles all methods
117
125
118 # Handle a custom msg from the front-end
126 # Handle a custom msg from the front-end
119 elif method == 'custom':
127 elif method == 'custom':
120 if 'custom_content' in data:
128 if 'custom_content' in data:
121 self._handle_custom_msg(data['custom_content'])
129 self._handle_custom_msg(data['custom_content'])
122
130
123 def _handle_custom_msg(self, content):
131 def _handle_custom_msg(self, content):
124 """Called when a custom msg is recieved."""
132 """Called when a custom msg is recieved."""
125 for handler in self._msg_callbacks:
133 for handler in self._msg_callbacks:
126 if callable(handler):
134 if callable(handler):
127 argspec = inspect.getargspec(handler)
135 argspec = inspect.getargspec(handler)
128 nargs = len(argspec[0])
136 nargs = len(argspec[0])
129
137
130 # Bound methods have an additional 'self' argument
138 # Bound methods have an additional 'self' argument
131 if isinstance(handler, types.MethodType):
139 if isinstance(handler, types.MethodType):
132 nargs -= 1
140 nargs -= 1
133
141
134 # Call the callback
142 # Call the callback
135 if nargs == 1:
143 if nargs == 1:
136 handler(content)
144 handler(content)
137 elif nargs == 2:
145 elif nargs == 2:
138 handler(self, content)
146 handler(self, content)
139 else:
147 else:
140 raise TypeError('Widget msg callback must ' \
148 raise TypeError('Widget msg callback must ' \
141 'accept 1 or 2 arguments, not %d.' % nargs)
149 'accept 1 or 2 arguments, not %d.' % nargs)
142
150
143
151
144 def _handle_recieve_state(self, sync_data):
152 def _handle_recieve_state(self, sync_data):
145 """Called when a state is recieved from the frontend."""
153 """Called when a state is recieved from the frontend."""
146 # Use _keys instead of keys - Don't get retrieve the css from the client side.
154 # Use _keys instead of keys - Don't get retrieve the css from the client side.
147 for name in self._keys:
155 for name in self._keys:
148 if name in sync_data:
156 if name in sync_data:
149 try:
157 try:
150 self._property_lock = (name, sync_data[name])
158 self._property_lock = (name, sync_data[name])
151 setattr(self, name, sync_data[name])
159 setattr(self, name, sync_data[name])
152 finally:
160 finally:
153 self._property_lock = (None, None)
161 self._property_lock = (None, None)
154
162
155
163
156 def _handle_property_changed(self, name, old, new):
164 def _handle_property_changed(self, name, old, new):
157 """Called when a property has been changed."""
165 """Called when a property has been changed."""
158 # Make sure this isn't information that the front-end just sent us.
166 # Make sure this isn't information that the front-end just sent us.
159 if self._property_lock[0] != name and self._property_lock[1] != new:
167 if self._property_lock[0] != name and self._property_lock[1] != new:
160 # Send new state to frontend
168 # Send new state to frontend
161 self.send_state(key=name)
169 self.send_state(key=name)
162
170
163 def _handle_displayed(self, **kwargs):
171 def _handle_displayed(self, **kwargs):
164 """Called when a view has been displayed for this widget instance
172 """Called when a view has been displayed for this widget instance
165
173
166 Parameters
174 Parameters
167 ----------
175 ----------
168 [view_name]: unicode (optional kwarg)
176 [view_name]: unicode (optional kwarg)
169 Name of the view that was displayed."""
177 Name of the view that was displayed."""
170 for handler in self._display_callbacks:
178 for handler in self._display_callbacks:
171 if callable(handler):
179 if callable(handler):
172 argspec = inspect.getargspec(handler)
180 argspec = inspect.getargspec(handler)
173 nargs = len(argspec[0])
181 nargs = len(argspec[0])
174
182
175 # Bound methods have an additional 'self' argument
183 # Bound methods have an additional 'self' argument
176 if isinstance(handler, types.MethodType):
184 if isinstance(handler, types.MethodType):
177 nargs -= 1
185 nargs -= 1
178
186
179 # Call the callback
187 # Call the callback
180 if nargs == 0:
188 if nargs == 0:
181 handler()
189 handler()
182 elif nargs == 1:
190 elif nargs == 1:
183 handler(self)
191 handler(self)
184 elif nargs == 2:
192 elif nargs == 2:
185 handler(self, kwargs.get('view_name', None))
193 handler(self, kwargs.get('view_name', None))
186 else:
194 else:
187 handler(self, **kwargs)
195 handler(self, **kwargs)
188
196
189 # Public methods
197 # Public methods
190 def send_state(self, key=None):
198 def send_state(self, key=None):
191 """Sends the widget state, or a piece of it, to the frontend.
199 """Sends the widget state, or a piece of it, to the frontend.
192
200
193 Parameters
201 Parameters
194 ----------
202 ----------
195 key : unicode (optional)
203 key : unicode (optional)
196 A single property's name to sync with the frontend.
204 A single property's name to sync with the frontend.
197 """
205 """
198 self._send({"method": "update",
206 self._send({"method": "update",
199 "state": self.get_state()})
207 "state": self.get_state()})
200
208
201 def get_state(self, key=None):
209 def get_state(self, key=None):
202 """Gets the widget state, or a piece of it.
210 """Gets the widget state, or a piece of it.
203
211
204 Parameters
212 Parameters
205 ----------
213 ----------
206 key : unicode (optional)
214 key : unicode (optional)
207 A single property's name to get.
215 A single property's name to get.
208 """
216 """
209 state = {}
217 state = {}
210
218
211 # If a key is provided, just send the state of that key.
219 # If a key is provided, just send the state of that key.
212 if key is None:
220 if key is None:
213 keys = self.keys[:]
221 keys = self.keys[:]
214 else:
222 else:
215 keys = [key]
223 keys = [key]
216 for k in keys:
224 for k in keys:
217 value = getattr(self, k)
225 value = getattr(self, k)
218
226
219 # a more elegant solution to encoding BaseWidgets would be
227 # a more elegant solution to encoding BaseWidgets would be
220 # to tap into the JSON encoder and teach it how to deal
228 # to tap into the JSON encoder and teach it how to deal
221 # with BaseWidget objects, or maybe just teach the JSON
229 # with BaseWidget objects, or maybe just teach the JSON
222 # encoder to look for a _repr_json property before giving
230 # encoder to look for a _repr_json property before giving
223 # up encoding
231 # up encoding
224 if isinstance(value, BaseWidget):
232 if isinstance(value, BaseWidget):
225 value = value.model_id
233 value = value.model_id
226 elif isinstance(value, list) and len(value)>0 and isinstance(value[0], BaseWidget):
234 elif isinstance(value, list) and len(value)>0 and isinstance(value[0], BaseWidget):
227 # assume all elements of the list are widgets
235 # assume all elements of the list are widgets
228 value = [i.model_id for i in value]
236 value = [i.model_id for i in value]
229 state[k] = value
237 state[k] = value
230 return state
238 return state
231
239
232
240
233 def send(self, content):
241 def send(self, content):
234 """Sends a custom msg to the widget model in the front-end.
242 """Sends a custom msg to the widget model in the front-end.
235
243
236 Parameters
244 Parameters
237 ----------
245 ----------
238 content : dict
246 content : dict
239 Content of the message to send.
247 Content of the message to send.
240 """
248 """
241 self._send({"method": "custom",
249 self._send({"method": "custom",
242 "custom_content": content})
250 "custom_content": content})
243
251
244
252
245 def on_msg(self, callback, remove=False):
253 def on_msg(self, callback, remove=False):
246 """Register a callback for when a custom msg is recieved from the front-end
254 """Register a callback for when a custom msg is recieved from the front-end
247
255
248 Parameters
256 Parameters
249 ----------
257 ----------
250 callback: method handler
258 callback: method handler
251 Can have a signature of:
259 Can have a signature of:
252 - callback(content)
260 - callback(content)
253 - callback(sender, content)
261 - callback(sender, content)
254 remove: bool
262 remove: bool
255 True if the callback should be unregistered."""
263 True if the callback should be unregistered."""
256 if remove and callback in self._msg_callbacks:
264 if remove and callback in self._msg_callbacks:
257 self._msg_callbacks.remove(callback)
265 self._msg_callbacks.remove(callback)
258 elif not remove and not callback in self._msg_callbacks:
266 elif not remove and not callback in self._msg_callbacks:
259 self._msg_callbacks.append(callback)
267 self._msg_callbacks.append(callback)
260
268
261
269
262 def on_displayed(self, callback, remove=False):
270 def on_displayed(self, callback, remove=False):
263 """Register a callback to be called when the widget has been displayed
271 """Register a callback to be called when the widget has been displayed
264
272
265 Parameters
273 Parameters
266 ----------
274 ----------
267 callback: method handler
275 callback: method handler
268 Can have a signature of:
276 Can have a signature of:
269 - callback()
277 - callback()
270 - callback(sender)
278 - callback(sender)
271 - callback(sender, view_name)
279 - callback(sender, view_name)
272 - callback(sender, **kwargs)
280 - callback(sender, **kwargs)
273 kwargs from display call passed through without modification.
281 kwargs from display call passed through without modification.
274 remove: bool
282 remove: bool
275 True if the callback should be unregistered."""
283 True if the callback should be unregistered."""
276 if remove and callback in self._display_callbacks:
284 if remove and callback in self._display_callbacks:
277 self._display_callbacks.remove(callback)
285 self._display_callbacks.remove(callback)
278 elif not remove and not callback in self._display_callbacks:
286 elif not remove and not callback in self._display_callbacks:
279 self._display_callbacks.append(callback)
287 self._display_callbacks.append(callback)
280
288
281
289
282 # Support methods
290 # Support methods
283 def _repr_widget_(self, **kwargs):
291 def _repr_widget_(self, **kwargs):
284 """Function that is called when `IPython.display.display` is called on
292 """Function that is called when `IPython.display.display` is called on
285 the widget.
293 the widget.
286
294
287 Parameters
295 Parameters
288 ----------
296 ----------
289 view_name: unicode (optional)
297 view_name: unicode (optional)
290 View to display in the frontend. Overrides default_view_name."""
298 View to display in the frontend. Overrides default_view_name."""
291 view_name = kwargs.get('view_name', self.default_view_name)
299 view_name = kwargs.get('view_name', self.default_view_name)
292
300
293 # Create a communication.
301 # Create a communication.
294 self._open_communication()
302 self._open_communication()
295
303
296 # Make sure model is syncronized
304 # Make sure model is syncronized
297 self.send_state()
305 self.send_state()
298
306
299 # Show view.
307 # Show view.
300 self._send({"method": "display", "view_name": view_name})
308 self._send({"method": "display", "view_name": view_name})
301 self._displayed = True
309 self._displayed = True
302 self._handle_displayed(**kwargs)
310 self._handle_displayed(**kwargs)
303
311
304
312
305 def _open_communication(self):
313 def _open_communication(self):
306 """Opens a communication with the front-end."""
314 """Opens a communication with the front-end."""
307 # Create a comm.
315 # Create a comm.
308 if self._comm is None:
316 if self._comm is None:
309 self._comm = Comm(target_name=self.target_name)
317 self._comm = Comm(target_name=self.target_name)
310 self._comm.on_msg(self._handle_msg)
318 self._comm.on_msg(self._handle_msg)
311 self._comm.on_close(self._close_communication)
319 self._comm.on_close(self._close_communication)
312
320
313 # first update
321 # first update
314 self.send_state()
322 self.send_state()
315
323
316
324
317 def _close_communication(self):
325 def _close_communication(self):
318 """Closes a communication with the front-end."""
326 """Closes a communication with the front-end."""
319 if self._comm is not None:
327 if self._comm is not None:
320 try:
328 try:
321 self._comm.close()
329 self._comm.close()
322 finally:
330 finally:
323 self._comm = None
331 self._comm = None
324
332
325
333
326 def _send(self, msg):
334 def _send(self, msg):
327 """Sends a message to the model in the front-end"""
335 """Sends a message to the model in the front-end"""
328 if self._comm is not None:
336 if self._comm is not None:
329 self._comm.send(msg)
337 self._comm.send(msg)
330 return True
338 return True
331 else:
339 else:
332 return False
340 return False
333
341
334
342
335 class ViewWidget(BaseWidget):
343 class ViewWidget(BaseWidget):
336 target_name = Unicode('ViewModel')
344 target_name = Unicode('ViewModel')
337
345
338 def __init__(self, widget, view):
346 def __init__(self, widget, view):
339 self.default_view_name = view
347 self.default_view_name = view
340 self.widget = widget
348 self.widget = widget
341
349
342
350
343 class Widget(BaseWidget):
351 class Widget(BaseWidget):
344 visible = Bool(True, help="Whether or not the widget is visible.")
352 visible = Bool(True, help="Whether or not the widget is visible.")
345
353
346 # Private/protected declarations
354 # Private/protected declarations
347 _css = Dict() # Internal CSS property dict
355 _css = Dict() # Internal CSS property dict
348
356
349 # Properties
357 _keys = ['visible', '_css']
350 @property
351 def keys(self):
352 keys = ['visible', '_css']
353 keys.extend(super(Widget, self).keys)
354 return keys
355
358
356 def get_css(self, key, selector=""):
359 def get_css(self, key, selector=""):
357 """Get a CSS property of the widget. Note, this function does not
360 """Get a CSS property of the widget. Note, this function does not
358 actually request the CSS from the front-end; Only properties that have
361 actually request the CSS from the front-end; Only properties that have
359 been set with set_css can be read.
362 been set with set_css can be read.
360
363
361 Parameters
364 Parameters
362 ----------
365 ----------
363 key: unicode
366 key: unicode
364 CSS key
367 CSS key
365 selector: unicode (optional)
368 selector: unicode (optional)
366 JQuery selector used when the CSS key/value was set.
369 JQuery selector used when the CSS key/value was set.
367 """
370 """
368 if selector in self._css and key in self._css[selector]:
371 if selector in self._css and key in self._css[selector]:
369 return self._css[selector][key]
372 return self._css[selector][key]
370 else:
373 else:
371 return None
374 return None
372
375
373
376
374 def set_css(self, *args, **kwargs):
377 def set_css(self, *args, **kwargs):
375 """Set one or more CSS properties of the widget (shared among all of the
378 """Set one or more CSS properties of the widget (shared among all of the
376 views). This function has two signatures:
379 views). This function has two signatures:
377 - set_css(css_dict, [selector=''])
380 - set_css(css_dict, [selector=''])
378 - set_css(key, value, [selector=''])
381 - set_css(key, value, [selector=''])
379
382
380 Parameters
383 Parameters
381 ----------
384 ----------
382 css_dict : dict
385 css_dict : dict
383 CSS key/value pairs to apply
386 CSS key/value pairs to apply
384 key: unicode
387 key: unicode
385 CSS key
388 CSS key
386 value
389 value
387 CSS value
390 CSS value
388 selector: unicode (optional)
391 selector: unicode (optional)
389 JQuery selector to use to apply the CSS key/value.
392 JQuery selector to use to apply the CSS key/value.
390 """
393 """
391 selector = kwargs.get('selector', '')
394 selector = kwargs.get('selector', '')
392
395
393 # Signature 1: set_css(css_dict, [selector=''])
396 # Signature 1: set_css(css_dict, [selector=''])
394 if len(args) == 1:
397 if len(args) == 1:
395 if isinstance(args[0], dict):
398 if isinstance(args[0], dict):
396 for (key, value) in args[0].items():
399 for (key, value) in args[0].items():
397 self.set_css(key, value, selector=selector)
400 self.set_css(key, value, selector=selector)
398 else:
401 else:
399 raise Exception('css_dict must be a dict.')
402 raise Exception('css_dict must be a dict.')
400
403
401 # Signature 2: set_css(key, value, [selector=''])
404 # Signature 2: set_css(key, value, [selector=''])
402 elif len(args) == 2 or len(args) == 3:
405 elif len(args) == 2 or len(args) == 3:
403
406
404 # Selector can be a positional arg if it's the 3rd value
407 # Selector can be a positional arg if it's the 3rd value
405 if len(args) == 3:
408 if len(args) == 3:
406 selector = args[2]
409 selector = args[2]
407 if selector not in self._css:
410 if selector not in self._css:
408 self._css[selector] = {}
411 self._css[selector] = {}
409
412
410 # Only update the property if it has changed.
413 # Only update the property if it has changed.
411 key = args[0]
414 key = args[0]
412 value = args[1]
415 value = args[1]
413 if not (key in self._css[selector] and value in self._css[selector][key]):
416 if not (key in self._css[selector] and value in self._css[selector][key]):
414 self._css[selector][key] = value
417 self._css[selector][key] = value
415 self.send_state('_css') # Send new state to client.
418 self.send_state('_css') # Send new state to client.
416 else:
419 else:
417 raise Exception('set_css only accepts 1-3 arguments')
420 raise Exception('set_css only accepts 1-3 arguments')
418
421
419
422
420 def add_class(self, class_name, selector=""):
423 def add_class(self, class_name, selector=""):
421 """Add class[es] to a DOM element
424 """Add class[es] to a DOM element
422
425
423 Parameters
426 Parameters
424 ----------
427 ----------
425 class_name: unicode
428 class_name: unicode
426 Class name(s) to add to the DOM element(s). Multiple class names
429 Class name(s) to add to the DOM element(s). Multiple class names
427 must be space separated.
430 must be space separated.
428 selector: unicode (optional)
431 selector: unicode (optional)
429 JQuery selector to select the DOM element(s) that the class(es) will
432 JQuery selector to select the DOM element(s) that the class(es) will
430 be added to.
433 be added to.
431 """
434 """
432 self.send({"msg_type": "add_class",
435 self.send({"msg_type": "add_class",
433 "class_list": class_name,
436 "class_list": class_name,
434 "selector": selector})
437 "selector": selector})
435
438
436
439
437 def remove_class(self, class_name, selector=""):
440 def remove_class(self, class_name, selector=""):
438 """Remove class[es] from a DOM element
441 """Remove class[es] from a DOM element
439
442
440 Parameters
443 Parameters
441 ----------
444 ----------
442 class_name: unicode
445 class_name: unicode
443 Class name(s) to remove from the DOM element(s). Multiple class
446 Class name(s) to remove from the DOM element(s). Multiple class
444 names must be space separated.
447 names must be space separated.
445 selector: unicode (optional)
448 selector: unicode (optional)
446 JQuery selector to select the DOM element(s) that the class(es) will
449 JQuery selector to select the DOM element(s) that the class(es) will
447 be removed from.
450 be removed from.
448 """
451 """
449 self.send({"msg_type": "remove_class",
452 self.send({"msg_type": "remove_class",
450 "class_list": class_name,
453 "class_list": class_name,
451 "selector": selector})
454 "selector": selector})
452
455
453
456
454 def view(self, view_name=None):
457 def view(self, view_name=None):
455 """Return a widget that can be displayed to display this widget using
458 """Return a widget that can be displayed to display this widget using
456 a non-default view"""
459 a non-default view"""
457 return ViewWidget(self, view_name)
460 return ViewWidget(self, view_name)
General Comments 0
You need to be logged in to leave comments. Login now