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