##// END OF EJS Templates
Added test
Added test

File last commit:

r17706:43ee7573 merge
r17938:904c2297
Show More
widget.py
478 lines | 17.4 KiB | text/x-python | PythonLexer
Jonathan Frederic
Dev meeting widget review day 1
r14586 """Base Widget class. Allows user to create widgets in the back-end that render
in the IPython notebook front-end.
Jonathan Frederic
Cleaned up Python widget code.
r14283 """
#-----------------------------------------------------------------------------
# Copyright (c) 2013, the IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
Jonathan Frederic
Implement a context manager as a property locking mechanism in Widget.
r14579 from contextlib import contextmanager
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 import collections
Jonathan Frederic
Added widget.py
r14223
MinRK
show traceback in widget handlers...
r15192 from IPython.core.getipython import get_ipython
Jonathan Frederic
Basic display logic...
r14229 from IPython.kernel.comm import Comm
from IPython.config import LoggingConfigurable
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple, Int, Set
Jonathan Frederic
Updates to widget.py...
r14232 from IPython.utils.py3compat import string_types
Jonathan Frederic
Cleaned up Python widget code.
r14283 #-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
Jonathan Frederic
Added new CallbackDispatcher class
r14658 class CallbackDispatcher(LoggingConfigurable):
MinRK
review pass on Python-side of widgets...
r14793 """A structure for registering and running callbacks"""
callbacks = List()
def __call__(self, *args, **kwargs):
"""Call all of the registered callbacks."""
Jonathan Frederic
Callback dispatcher return callback value....
r14721 value = None
MinRK
review pass on Python-side of widgets...
r14793 for callback in self.callbacks:
try:
local_value = callback(*args, **kwargs)
except Exception as e:
MinRK
show traceback in widget handlers...
r15192 ip = get_ipython()
if ip is None:
self.log.warn("Exception in callback %s: %s", callback, e, exc_info=True)
else:
ip.showtraceback()
MinRK
review pass on Python-side of widgets...
r14793 else:
Jonathan Frederic
Callback dispatcher return callback value....
r14721 value = local_value if local_value is not None else value
return value
Jonathan Frederic
Added new CallbackDispatcher class
r14658
def register_callback(self, callback, remove=False):
"""(Un)Register a callback
Parameters
----------
callback: method handle
MinRK
review pass on Python-side of widgets...
r14793 Method to be registered or unregistered.
Jonathan Frederic
Added new CallbackDispatcher class
r14658 remove=False: bool
MinRK
review pass on Python-side of widgets...
r14793 Whether to unregister the callback."""
Jonathan Frederic
Added new CallbackDispatcher class
r14658 # (Un)Register the callback.
MinRK
review pass on Python-side of widgets...
r14793 if remove and callback in self.callbacks:
self.callbacks.remove(callback)
elif not remove and callback not in self.callbacks:
self.callbacks.append(callback)
Jonathan Frederic
Added widget.py
r14223
MinRK
show traceback in widget handlers...
r15192 def _show_traceback(method):
"""decorator for showing tracebacks in IPython"""
def m(self, *args, **kwargs):
try:
return(method(self, *args, **kwargs))
except Exception as e:
ip = get_ipython()
if ip is None:
self.log.warn("Exception in widget method %s: %s", method, e, exc_info=True)
else:
ip.showtraceback()
return m
Jonathan Frederic
Added new CallbackDispatcher class
r14658
class Widget(LoggingConfigurable):
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
# Class attributes
#-------------------------------------------------------------------------
MinRK
review pass on Python-side of widgets...
r14793 _widget_construction_callback = None
Jonathan Frederic
Dev meeting widget review day 1
r14586 widgets = {}
Jonathan Frederic
Added event for widget construction
r14478
MinRK
review pass on Python-side of widgets...
r14793 @staticmethod
Jonathan Frederic
Added event for widget construction
r14478 def on_widget_constructed(callback):
MinRK
review pass on Python-side of widgets...
r14793 """Registers a callback to be called when a widget is constructed.
Jonathan Frederic
More PEP8 changes
r14607
The callback must have the following signature:
Jonathan Frederic
Added event for widget construction
r14478 callback(widget)"""
MinRK
review pass on Python-side of widgets...
r14793 Widget._widget_construction_callback = callback
Jonathan Frederic
Added event for widget construction
r14478
MinRK
review pass on Python-side of widgets...
r14793 @staticmethod
Jonathan Frederic
s/_handle_widget_constructed/_call_widget_constructed
r14542 def _call_widget_constructed(widget):
MinRK
review pass on Python-side of widgets...
r14793 """Static method, called when a widget is constructed."""
if Widget._widget_construction_callback is not None and callable(Widget._widget_construction_callback):
Widget._widget_construction_callback(widget)
Jonathan Frederic
Added event for widget construction
r14478
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
# Traits
#-------------------------------------------------------------------------
Jonathan Frederic
s/model_name/_model_name
r14896 _model_name = Unicode('WidgetModel', help="""Name of the backbone model
Jonathan Frederic
Dev meeting widget review day 1
r14586 registered in the front-end to create and sync this widget with.""")
Jason Grout
Default view should be the base widget view class
r17590 _view_name = Unicode('WidgetView', help="""Default view registered in the front-end
Jonathan Frederic
sync=True isntead of a keys list
r14588 to use to represent the widget.""", sync=True)
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 comm = Instance('IPython.kernel.comm.Comm')
MinRK
review pass on Python-side of widgets...
r14793
Jonathan Frederic
Added msg_throttle sync=True widget traitlet
r15368 msg_throttle = Int(3, sync=True, help="""Maximum number of msgs the
front-end can send before receiving an idle msg from the back-end.""")
MinRK
review pass on Python-side of widgets...
r14793
keys = List()
def _keys_default(self):
return [name for name in self.traits(sync=True)]
_property_lock = Tuple((None, None))
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 _send_state_lock = Int(0)
_states_to_send = Set(allow_none=False)
MinRK
review pass on Python-side of widgets...
r14793 _display_callbacks = Instance(CallbackDispatcher, ())
_msg_callbacks = Instance(CallbackDispatcher, ())
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
# (Con/de)structor
MinRK
review pass on Python-side of widgets...
r14793 #-------------------------------------------------------------------------
Jonathan Frederic
Allow parent to be set after construction......
r14310 def __init__(self, **kwargs):
Jonathan Frederic
More PEP8 changes
r14607 """Public constructor"""
Sylvain Corlay
allowing widet id to be set externally
r17616 self._model_id = kwargs.pop('model_id', None)
Jonathan Frederic
s/Widget/DOMWidget s/BaseWidget/Widget
r14540 super(Widget, self).__init__(**kwargs)
Jonathan Frederic
Added event for widget construction
r14478
Jason Grout
Remove the automatic _children_attr and _children_lists_attr....
r14487 self.on_trait_change(self._handle_property_changed, self.keys)
Jonathan Frederic
s/_handle_widget_constructed/_call_widget_constructed
r14542 Widget._call_widget_constructed(self)
Jason Grout
Automatically open a comm on creation of widgets...
r17612 self.open()
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Jonathan Frederic
Added widget.py
r14223 def __del__(self):
Jonathan Frederic
Cleaned up Python widget code.
r14283 """Object disposal"""
Jonathan Frederic
Added widget.py
r14223 self.close()
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
# Properties
MinRK
review pass on Python-side of widgets...
r14793 #-------------------------------------------------------------------------
Jonathan Frederic
Dev meeting widget review day 1
r14586
Jason Grout
Automatically open a comm on creation of widgets...
r17612 def open(self):
"""Open a comm to the frontend if one isn't already open."""
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 if self.comm is None:
Sylvain Corlay
allowing widet id to be set externally
r17616 if self._model_id is None:
self.comm = Comm(target_name=self._model_name)
self._model_id = self.model_id
else:
self.comm = Comm(target_name=self._model_name, comm_id=self._model_id)
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 self.comm.on_msg(self._handle_msg)
Jonathan Frederic
Dev meeting widget review day 1
r14586 Widget.widgets[self.model_id] = self
# first update
self.send_state()
Jason Grout
Automatically open a comm on creation of widgets...
r17612
Jonathan Frederic
Re-decoupled comm_id from widget models
r14512 @property
def model_id(self):
Jonathan Frederic
Added doc strings to properties in widget.py
r14654 """Gets the model id of this widget.
If a Comm doesn't exist yet, a Comm will be created automagically."""
Jonathan Frederic
Fixed typo in model_id property
r14527 return self.comm.comm_id
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
# Methods
MinRK
review pass on Python-side of widgets...
r14793 #-------------------------------------------------------------------------
Jonathan Frederic
Reorganized attrs in widget.py
r14653 def close(self):
MinRK
review pass on Python-side of widgets...
r14793 """Close method.
Jonathan Frederic
Updates to widget.py...
r14232
sylvain.corlay
decoupling the comm lifetime from the widget lifetime
r17405 Closes the underlying comm.
Jonathan Frederic
Reorganized attrs in widget.py
r14653 When the comm is closed, all of the widget views are automatically
removed from the front-end."""
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 if self.comm is not None:
MinRK
avoid unregistering widget model twice...
r17540 Widget.widgets.pop(self.model_id, None)
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 self.comm.close()
self.comm = None
Sylvain Corlay
del Widget.widgets[seld.model_id] in close rather than in __del__
r17465
Jonathan Frederic
Cleaned up Python widget code.
r14283 def send_state(self, key=None):
Jonathan Frederic
Dev meeting widget review day 1
r14586 """Sends the widget state, or a piece of it, to the front-end.
Jonathan Frederic
Cleaned up Python widget code.
r14283
Parameters
----------
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 key : unicode, or iterable (optional)
A single property's name or iterable of property names to sync with the front-end.
Jonathan Frederic
Cleaned up Python widget code.
r14283 """
Jonathan Frederic
Halign dict colons
r14610 self._send({
"method" : "update",
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 "state" : self.get_state(key=key)
Jonathan Frederic
Halign dict colons
r14610 })
Jonathan Frederic
Cleaned up Python widget code.
r14283
Jason Grout
Intermediate changes to javascript side of backbone widgets
r14486 def get_state(self, key=None):
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485 """Gets the widget state, or a piece of it.
Jonathan Frederic
Cleaned up Python widget code.
r14283
Parameters
----------
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 key : unicode or iterable (optional)
A single property's name or iterable of property names to get.
Jonathan Frederic
Cleaned up Python widget code.
r14283 """
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 if key is None:
keys = self.keys
elif isinstance(key, string_types):
keys = [key]
elif isinstance(key, collections.Iterable):
keys = key
else:
raise ValueError("key must be a string, an iterable of keys, or None")
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 state = {}
for k in keys:
Jason Grout
Make the widget property_lock store the JSON state, not the original object...
r17674 f = self.trait_metadata(k, 'to_json', self._trait_to_json)
Jason Grout
Simplify the code for picking json serialization functions to expose the logic better
r17294 value = getattr(self, k)
state[k] = f(value)
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 return state
Jonathan Frederic
Added support for custom widget msgs
r14387 def send(self, content):
"""Sends a custom msg to the widget model in the front-end.
Parameters
----------
content : dict
Content of the message to send.
"""
Jonathan Frederic
s/custom_content/content
r14655 self._send({"method": "custom", "content": content})
Jonathan Frederic
Added support for custom widget msgs
r14387
Jonathan Frederic
Dev meeting widget review day 1
r14586 def on_msg(self, callback, remove=False):
MinRK
review pass on Python-side of widgets...
r14793 """(Un)Register a custom msg receive callback.
Jonathan Frederic
Added support for custom widget msgs
r14387
Parameters
----------
MinRK
review pass on Python-side of widgets...
r14793 callback: callable
Thomas Kluyver
Fix some formatting in widget docstrings
r14915 callback will be passed two arguments when a message arrives::
MinRK
review pass on Python-side of widgets...
r14793 callback(widget, content)
Thomas Kluyver
Fix some formatting in widget docstrings
r14915
Jonathan Frederic
Added support for custom widget msgs
r14387 remove: bool
True if the callback should be unregistered."""
Jonathan Frederic
Added new CallbackDispatcher class
r14658 self._msg_callbacks.register_callback(callback, remove=remove)
Jonathan Frederic
Added support for custom widget msgs
r14387
Jonathan Frederic
Added on_display callback
r14330 def on_displayed(self, callback, remove=False):
Jonathan Frederic
More PEP8 changes
r14607 """(Un)Register a widget displayed callback.
Jonathan Frederic
Added on_display callback
r14330
Jonathan Frederic
Fixed doc string comments, removed extra space
r14332 Parameters
----------
Jonathan Frederic
Added on_display callback
r14330 callback: method handler
Thomas Kluyver
Fix some formatting in widget docstrings
r14915 Must have a signature of::
MinRK
review pass on Python-side of widgets...
r14793 callback(widget, **kwargs)
Thomas Kluyver
Fix some formatting in widget docstrings
r14915
MinRK
review pass on Python-side of widgets...
r14793 kwargs from display are passed through without modification.
Jonathan Frederic
Added on_display callback
r14330 remove: bool
True if the callback should be unregistered."""
Jonathan Frederic
Added new CallbackDispatcher class
r14658 self._display_callbacks.register_callback(callback, remove=remove)
Jonathan Frederic
Added on_display callback
r14330
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
Jonathan Frederic
Cleaned up Python widget code.
r14283 # Support methods
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
@contextmanager
Jonathan Frederic
Fixed name conflict with _property_lock
r14659 def _lock_property(self, key, value):
Jonathan Frederic
Reorganized attrs in widget.py
r14653 """Lock a property-value pair.
Jason Grout
Make the widget property_lock store the JSON state, not the original object...
r17674 The value should be the JSON state of the property.
Jonathan Frederic
Reorganized attrs in widget.py
r14653 NOTE: This, in addition to the single lock for all state changes, is
flawed. In the future we may want to look into buffering state changes
back to the front-end."""
self._property_lock = (key, value)
try:
yield
finally:
self._property_lock = (None, None)
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 @contextmanager
def hold_sync(self):
"""Hold syncing any state until the context manager is released"""
# We increment a value so that this can be nested. Syncing will happen when
# all levels have been released.
self._send_state_lock += 1
try:
yield
finally:
self._send_state_lock -=1
if self._send_state_lock == 0:
self.send_state(self._states_to_send)
self._states_to_send.clear()
Jonathan Frederic
Reorganized attrs in widget.py
r14653 def _should_send_property(self, key, value):
"""Check the property lock (property_lock)"""
Jason Grout
Make the widget property_lock store the JSON state, not the original object...
r17674 to_json = self.trait_metadata(key, 'to_json', self._trait_to_json)
if (key == self._property_lock[0]
and to_json(value) == self._property_lock[1]):
Jason Grout
Before syncing a widget's state, check first for the property lock, then for the widget state lock
r17623 return False
elif self._send_state_lock > 0:
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 self._states_to_send.add(key)
return False
Jason Grout
Before syncing a widget's state, check first for the property lock, then for the widget state lock
r17623 else:
return True
Jonathan Frederic
Reorganized attrs in widget.py
r14653
# Event handlers
MinRK
show traceback in widget handlers...
r15192 @_show_traceback
Jonathan Frederic
Reorganized attrs in widget.py
r14653 def _handle_msg(self, msg):
"""Called when a msg is received from the front-end"""
data = msg['content']['data']
method = data['method']
if not method in ['backbone', 'custom']:
self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
# Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
if method == 'backbone' and 'sync_data' in data:
sync_data = data['sync_data']
self._handle_receive_state(sync_data) # handles all methods
# Handle a custom msg from the front-end
elif method == 'custom':
Jonathan Frederic
s/custom_content/content
r14655 if 'content' in data:
self._handle_custom_msg(data['content'])
Jonathan Frederic
Reorganized attrs in widget.py
r14653
def _handle_receive_state(self, sync_data):
"""Called when a state is received from the front-end."""
for name in self.keys:
if name in sync_data:
Jason Grout
Make the widget property_lock store the JSON state, not the original object...
r17674 json_value = sync_data[name]
from_json = self.trait_metadata(name, 'from_json', self._trait_from_json)
with self._lock_property(name, json_value):
setattr(self, name, from_json(json_value))
Jonathan Frederic
Reorganized attrs in widget.py
r14653
def _handle_custom_msg(self, content):
"""Called when a custom msg is received."""
MinRK
review pass on Python-side of widgets...
r14793 self._msg_callbacks(self, content)
Jonathan Frederic
Reorganized attrs in widget.py
r14653
def _handle_property_changed(self, name, old, new):
"""Called when a property has been changed."""
# Make sure this isn't information that the front-end just sent us.
if self._should_send_property(name, new):
# Send new state to front-end
self.send_state(key=name)
def _handle_displayed(self, **kwargs):
"""Called when a view has been displayed for this widget instance"""
MinRK
review pass on Python-side of widgets...
r14793 self._display_callbacks(self, **kwargs)
Jonathan Frederic
Reorganized attrs in widget.py
r14653
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 def _trait_to_json(self, x):
"""Convert a trait value to json
Jonathan Frederic
Reorganized attrs in widget.py
r14653
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 Traverse lists/tuples and dicts and serialize their values as well.
Replace any widgets with their model_id
"""
Jonathan Frederic
ict comprehension and list comprehension in pack/unpack widgets
r14656 if isinstance(x, dict):
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 return {k: self._trait_to_json(v) for k, v in x.items()}
Jonathan Frederic
Changed children list to CTuple....
r15465 elif isinstance(x, (list, tuple)):
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 return [self._trait_to_json(v) for v in x]
Jonathan Frederic
ict comprehension and list comprehension in pack/unpack widgets
r14656 elif isinstance(x, Widget):
Jason Grout
Prepend a sentinel value to model ids to distinguish them from normal UUIDs (from Sylvain Corlay).
r17262 return "IPY_MODEL_" + x.model_id
Jonathan Frederic
Reorganized attrs in widget.py
r14653 else:
Jonathan Frederic
Document in widget packing that vaues must be JSON-able.
r14657 return x # Value must be JSON-able
Jonathan Frederic
Reorganized attrs in widget.py
r14653
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 def _trait_from_json(self, x):
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 """Convert json values to objects
Jonathan Frederic
Reorganized attrs in widget.py
r14653
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 Replace any strings representing valid model id values to Widget references.
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 """
Jonathan Frederic
ict comprehension and list comprehension in pack/unpack widgets
r14656 if isinstance(x, dict):
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 return {k: self._trait_from_json(v) for k, v in x.items()}
Jonathan Frederic
Changed children list to CTuple....
r15465 elif isinstance(x, (list, tuple)):
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 return [self._trait_from_json(v) for v in x]
Jason Grout
Prepend a sentinel value to model ids to distinguish them from normal UUIDs (from Sylvain Corlay).
r17262 elif isinstance(x, string_types) and x.startswith('IPY_MODEL_') and x[10:] in Widget.widgets:
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 # we want to support having child widgets at any level in a hierarchy
# trusting that a widget UUID will not appear out in the wild
return Widget.widgets[x]
Jonathan Frederic
Reorganized attrs in widget.py
r14653 else:
Jonathan Frederic
ict comprehension and list comprehension in pack/unpack widgets
r14656 return x
Jonathan Frederic
Reorganized attrs in widget.py
r14653
Jonathan Frederic
Dev meeting widget review day 1
r14586 def _ipython_display_(self, **kwargs):
Jonathan Frederic
More PEP8 changes
r14607 """Called when `IPython.display.display` is called on the widget."""
Jonathan Frederic
Fixed _send so it can open a comm if needed....
r14548 # Show view. By sending a display message, the comm is opened and the
# initial state is sent.
Jonathan Frederic
Remove view_name from display
r14549 self._send({"method": "display"})
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485 self._handle_displayed(**kwargs)
Jonathan Frederic
Decoupled Python Widget from Comm...
r14479
def _send(self, msg):
Jonathan Frederic
More PEP8 changes
r14607 """Sends a message to the model in the front-end."""
Jonathan Frederic
Fixed _send so it can open a comm if needed....
r14548 self.comm.send(msg)
Jonathan Frederic
Moved view widget into widget.py
r14516
Jonathan Frederic
s/Widget/DOMWidget s/BaseWidget/Widget
r14540 class DOMWidget(Widget):
MinRK
review pass on Python-side of widgets...
r14793 visible = Bool(True, help="Whether the widget is visible.", sync=True)
Jonathan Frederic
Change css dict to a list,...
r16816 _css = List(sync=True) # Internal CSS property list: (selector, key, value)
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
def get_css(self, key, selector=""):
Jonathan Frederic
Add a comment that explains the notion of the default element...
r14581 """Get a CSS property of the widget.
Note: This function does not actually request the CSS from the
front-end; Only properties that have been set with set_css can be read.
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Parameters
----------
key: unicode
CSS key
selector: unicode (optional)
JQuery selector used when the CSS key/value was set.
"""
if selector in self._css and key in self._css[selector]:
return self._css[selector][key]
else:
return None
MinRK
review pass on Python-side of widgets...
r14793 def set_css(self, dict_or_key, value=None, selector=''):
Jonathan Frederic
Add a comment that explains the notion of the default element...
r14581 """Set one or more CSS properties of the widget.
This function has two signatures:
Jonathan Frederic
Fixed comments for optional kwargs so they are redundant.
r14551 - set_css(css_dict, selector='')
- set_css(key, value, selector='')
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Parameters
----------
css_dict : dict
CSS key/value pairs to apply
key: unicode
CSS key
MinRK
review pass on Python-side of widgets...
r14793 value:
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485 CSS value
MinRK
review pass on Python-side of widgets...
r14793 selector: unicode (optional, kwarg only)
Jonathan Frederic
Add a comment that explains the notion of the default element...
r14581 JQuery selector to use to apply the CSS key/value. If no selector
is provided, an empty selector is used. An empty selector makes the
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 front-end try to apply the css to a default element. The default
element is an attribute unique to each view, which is a DOM element
of the view that should be styled with common CSS (see
`$el_to_style` in the Javascript code).
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485 """
MinRK
review pass on Python-side of widgets...
r14793 if value is None:
css_dict = dict_or_key
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485 else:
MinRK
review pass on Python-side of widgets...
r14793 css_dict = {dict_or_key: value}
for (key, value) in css_dict.items():
Jonathan Frederic
Change css dict to a list,...
r16816 # First remove the selector/key pair from the css list if it exists.
# Then add the selector/key pair and new value to the bottom of the
# list.
self._css = [x for x in self._css if not (x[0]==selector and x[1]==key)]
self._css += [(selector, key, value)]
MinRK
review pass on Python-side of widgets...
r14793 self.send_state('_css')
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Jonathan Frederic
add/remove_class now can accept a list of classes
r14539 def add_class(self, class_names, selector=""):
Jonathan Frederic
More PEP8 changes
r14607 """Add class[es] to a DOM element.
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Parameters
----------
Jonathan Frederic
add/remove_class now can accept a list of classes
r14539 class_names: unicode or list
Class name(s) to add to the DOM element(s).
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485 selector: unicode (optional)
JQuery selector to select the DOM element(s) that the class(es) will
be added to.
"""
Jonathan Frederic
add/remove_class now can accept a list of classes
r14539 class_list = class_names
Jonathan Frederic
Changed children list to CTuple....
r15465 if isinstance(class_list, (list, tuple)):
Jonathan Frederic
add/remove_class now can accept a list of classes
r14539 class_list = ' '.join(class_list)
Jonathan Frederic
Halign dict colons
r14610 self.send({
"msg_type" : "add_class",
"class_list" : class_list,
"selector" : selector
})
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Jonathan Frederic
add/remove_class now can accept a list of classes
r14539 def remove_class(self, class_names, selector=""):
Jonathan Frederic
More PEP8 changes
r14607 """Remove class[es] from a DOM element.
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Parameters
----------
Jonathan Frederic
add/remove_class now can accept a list of classes
r14539 class_names: unicode or list
Class name(s) to remove from the DOM element(s).
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485 selector: unicode (optional)
JQuery selector to select the DOM element(s) that the class(es) will
be removed from.
"""
Jonathan Frederic
add/remove_class now can accept a list of classes
r14539 class_list = class_names
Jonathan Frederic
Changed children list to CTuple....
r15465 if isinstance(class_list, (list, tuple)):
Jonathan Frederic
add/remove_class now can accept a list of classes
r14539 class_list = ' '.join(class_list)
Jonathan Frederic
Halign dict colons
r14610 self.send({
"msg_type" : "remove_class",
"class_list" : class_list,
"selector" : selector,
})