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