##// END OF EJS Templates
Remove text repr of js includes.
Jonathan Frederic -
Show More
@@ -1,253 +1,253 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
20
21 import IPython
21 import IPython
22 from IPython.kernel.comm import Comm
22 from IPython.kernel.comm import Comm
23 from IPython.config import LoggingConfigurable
23 from IPython.config import LoggingConfigurable
24 from IPython.utils.traitlets import Unicode, Dict, List, Instance, Bool
24 from IPython.utils.traitlets import Unicode, Dict, List, Instance, Bool
25 from IPython.display import Javascript, display
25 from IPython.display import Javascript, display
26 from IPython.utils.py3compat import string_types
26 from IPython.utils.py3compat import string_types
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Shared
29 # Shared
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 def init_widget_js():
31 def init_widget_js():
32 path = os.path.split(os.path.abspath( __file__ ))[0]
32 path = os.path.split(os.path.abspath( __file__ ))[0]
33 for filepath in glob(os.path.join(path, "*.py")):
33 for filepath in glob(os.path.join(path, "*.py")):
34 filename = os.path.split(filepath)[1]
34 filename = os.path.split(filepath)[1]
35 name = filename.rsplit('.', 1)[0]
35 name = filename.rsplit('.', 1)[0]
36 if not (name == 'widget' or name == '__init__') and name.startswith('widget_'):
36 if not (name == 'widget' or name == '__init__') and name.startswith('widget_'):
37 # Remove 'widget_' from the start of the name before compiling the path.
37 # Remove 'widget_' from the start of the name before compiling the path.
38 js_path = '/static/notebook/js/widgets/%s.js' % name[7:]
38 js_path = '/static/notebook/js/widgets/%s.js' % name[7:]
39 display(Javascript(data='$.getScript("%s");' % js_path))
39 display(Javascript(data='$.getScript("%s");' % js_path), exclude="text/plain")
40
40
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Classes
43 # Classes
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 class Widget(LoggingConfigurable):
45 class Widget(LoggingConfigurable):
46
46
47 # Public declarations
47 # Public declarations
48 target_name = Unicode('widget', help="""Name of the backbone model
48 target_name = Unicode('widget', help="""Name of the backbone model
49 registered in the frontend to create and sync this widget with.""")
49 registered in the frontend to create and sync this widget with.""")
50 default_view_name = Unicode(help="""Default view registered in the frontend
50 default_view_name = Unicode(help="""Default view registered in the frontend
51 to use to represent the widget.""")
51 to use to represent the widget.""")
52 parent = Instance('IPython.html.widgets.widget.Widget')
52 parent = Instance('IPython.html.widgets.widget.Widget')
53 visible = Bool(True, help="Whether or not the widget is visible.")
53 visible = Bool(True, help="Whether or not the widget is visible.")
54
54
55 def _parent_changed(self, name, old, new):
55 def _parent_changed(self, name, old, new):
56 if self._displayed:
56 if self._displayed:
57 raise Exception('Parent cannot be set because widget has been displayed.')
57 raise Exception('Parent cannot be set because widget has been displayed.')
58 elif new == self:
58 elif new == self:
59 raise Exception('Parent cannot be set to self.')
59 raise Exception('Parent cannot be set to self.')
60 else:
60 else:
61
61
62 # Parent/child association
62 # Parent/child association
63 if new is not None and not self in new._children:
63 if new is not None and not self in new._children:
64 new._children.append(self)
64 new._children.append(self)
65 if old is not None and self in old._children:
65 if old is not None and self in old._children:
66 old._children.remove(self)
66 old._children.remove(self)
67
67
68 # Private/protected declarations
68 # Private/protected declarations
69 _keys = []
69 _keys = []
70 _property_lock = False
70 _property_lock = False
71 _css = Dict()
71 _css = Dict()
72 _displayed = False
72 _displayed = False
73 _comm = None
73 _comm = None
74
74
75
75
76 def __init__(self, **kwargs):
76 def __init__(self, **kwargs):
77 """Public constructor
77 """Public constructor
78
78
79 Parameters
79 Parameters
80 ----------
80 ----------
81 parent : Widget instance (optional)
81 parent : Widget instance (optional)
82 Widget that this widget instance is child of. When the widget is
82 Widget that this widget instance is child of. When the widget is
83 displayed in the frontend, it's corresponding view will be made
83 displayed in the frontend, it's corresponding view will be made
84 child of the parent's view if the parent's view exists already. If
84 child of the parent's view if the parent's view exists already. If
85 the parent's view is displayed, it will automatically display this
85 the parent's view is displayed, it will automatically display this
86 widget's default view as it's child. The default view can be set
86 widget's default view as it's child. The default view can be set
87 via the default_view_name property.
87 via the default_view_name property.
88 """
88 """
89 self._children = []
89 self._children = []
90 super(Widget, self).__init__(**kwargs)
90 super(Widget, self).__init__(**kwargs)
91
91
92 # Register after init to allow default values to be specified
92 # Register after init to allow default values to be specified
93 self.on_trait_change(self._handle_property_changed, self.keys)
93 self.on_trait_change(self._handle_property_changed, self.keys)
94
94
95
95
96 def __del__(self):
96 def __del__(self):
97 """Object disposal"""
97 """Object disposal"""
98 self.close()
98 self.close()
99
99
100
100
101 def close(self):
101 def close(self):
102 """Close method. Closes the widget which closes the underlying comm.
102 """Close method. Closes the widget which closes the underlying comm.
103 When the comm is closed, all of the widget views are automatically
103 When the comm is closed, all of the widget views are automatically
104 removed from the frontend."""
104 removed from the frontend."""
105 self._comm.close()
105 self._comm.close()
106 del self._comm
106 del self._comm
107
107
108
108
109 # Properties
109 # Properties
110 def _get_keys(self):
110 def _get_keys(self):
111 keys = ['_css', 'visible']
111 keys = ['_css', 'visible']
112 keys.extend(self._keys)
112 keys.extend(self._keys)
113 return keys
113 return keys
114 keys = property(_get_keys)
114 keys = property(_get_keys)
115
115
116
116
117 # Event handlers
117 # Event handlers
118 def _handle_msg(self, msg):
118 def _handle_msg(self, msg):
119 """Called when a msg is recieved from the frontend"""
119 """Called when a msg is recieved from the frontend"""
120 # Handle backbone sync methods CREATE, PATCH, and UPDATE
120 # Handle backbone sync methods CREATE, PATCH, and UPDATE
121 sync_method = msg['content']['data']['sync_method']
121 sync_method = msg['content']['data']['sync_method']
122 sync_data = msg['content']['data']['sync_data']
122 sync_data = msg['content']['data']['sync_data']
123 self._handle_recieve_state(sync_data) # handles all methods
123 self._handle_recieve_state(sync_data) # handles all methods
124
124
125
125
126 def _handle_recieve_state(self, sync_data):
126 def _handle_recieve_state(self, sync_data):
127 """Called when a state is recieved from the frontend."""
127 """Called when a state is recieved from the frontend."""
128 self._property_lock = True
128 self._property_lock = True
129 try:
129 try:
130
130
131 # Use _keys instead of keys - Don't get retrieve the css from the client side.
131 # Use _keys instead of keys - Don't get retrieve the css from the client side.
132 for name in self._keys:
132 for name in self._keys:
133 if name in sync_data:
133 if name in sync_data:
134 setattr(self, name, sync_data[name])
134 setattr(self, name, sync_data[name])
135 finally:
135 finally:
136 self._property_lock = False
136 self._property_lock = False
137
137
138
138
139 def _handle_property_changed(self, name, old, new):
139 def _handle_property_changed(self, name, old, new):
140 """Called when a proeprty has been changed."""
140 """Called when a proeprty has been changed."""
141 if not self._property_lock and self._comm is not None:
141 if not self._property_lock and self._comm is not None:
142 # TODO: Validate properties.
142 # TODO: Validate properties.
143 # Send new state to frontend
143 # Send new state to frontend
144 self.send_state(key=name)
144 self.send_state(key=name)
145
145
146
146
147 def _handle_close(self):
147 def _handle_close(self):
148 """Called when the comm is closed by the frontend."""
148 """Called when the comm is closed by the frontend."""
149 self._comm = None
149 self._comm = None
150
150
151
151
152 # Public methods
152 # Public methods
153 def send_state(self, key=None):
153 def send_state(self, key=None):
154 """Sends the widget state, or a piece of it, to the frontend.
154 """Sends the widget state, or a piece of it, to the frontend.
155
155
156 Parameters
156 Parameters
157 ----------
157 ----------
158 key : unicode (optional)
158 key : unicode (optional)
159 A single property's name to sync with the frontend.
159 A single property's name to sync with the frontend.
160 """
160 """
161 if self._comm is not None:
161 if self._comm is not None:
162 state = {}
162 state = {}
163
163
164 # If a key is provided, just send the state of that key.
164 # If a key is provided, just send the state of that key.
165 keys = []
165 keys = []
166 if key is None:
166 if key is None:
167 keys.extend(self.keys)
167 keys.extend(self.keys)
168 else:
168 else:
169 keys.append(key)
169 keys.append(key)
170 for key in self.keys:
170 for key in self.keys:
171 try:
171 try:
172 state[key] = getattr(self, key)
172 state[key] = getattr(self, key)
173 except Exception as e:
173 except Exception as e:
174 pass # Eat errors, nom nom nom
174 pass # Eat errors, nom nom nom
175 self._comm.send({"method": "update",
175 self._comm.send({"method": "update",
176 "state": state})
176 "state": state})
177
177
178
178
179 def get_css(self, key, selector=""):
179 def get_css(self, key, selector=""):
180 """Get a CSS property of the widget views (shared among all of the
180 """Get a CSS property of the widget views (shared among all of the
181 views)
181 views)
182
182
183 Parameters
183 Parameters
184 ----------
184 ----------
185 key: unicode
185 key: unicode
186 CSS key
186 CSS key
187 selector: unicode (optional)
187 selector: unicode (optional)
188 JQuery selector used when the CSS key/value was set.
188 JQuery selector used when the CSS key/value was set.
189 """
189 """
190 if selector in self._css and key in self._css[selector]:
190 if selector in self._css and key in self._css[selector]:
191 return self._css[selector][key]
191 return self._css[selector][key]
192 else:
192 else:
193 return None
193 return None
194
194
195
195
196 def set_css(self, key, value, selector=""):
196 def set_css(self, key, value, selector=""):
197 """Set a CSS property of the widget views (shared among all of the
197 """Set a CSS property of the widget views (shared among all of the
198 views)
198 views)
199
199
200 Parameters
200 Parameters
201 ----------
201 ----------
202 key: unicode
202 key: unicode
203 CSS key
203 CSS key
204 value
204 value
205 CSS value
205 CSS value
206 selector: unicode (optional)
206 selector: unicode (optional)
207 JQuery selector to use to apply the CSS key/value.
207 JQuery selector to use to apply the CSS key/value.
208 """
208 """
209 if selector not in self._css:
209 if selector not in self._css:
210 self._css[selector] = {}
210 self._css[selector] = {}
211
211
212 # Only update the property if it has changed.
212 # Only update the property if it has changed.
213 if not (key in self._css[selector] and value in self._css[selector][key]):
213 if not (key in self._css[selector] and value in self._css[selector][key]):
214 self._css[selector][key] = value
214 self._css[selector][key] = value
215 self.send_state() # Send new state to client.
215 self.send_state() # Send new state to client.
216
216
217
217
218 # Support methods
218 # Support methods
219 def _repr_widget_(self, view_name=None):
219 def _repr_widget_(self, view_name=None):
220 """Function that is called when `IPython.display.display` is called on
220 """Function that is called when `IPython.display.display` is called on
221 the widget.
221 the widget.
222
222
223 Parameters
223 Parameters
224 ----------
224 ----------
225 view_name: unicode (optional)
225 view_name: unicode (optional)
226 View to display in the frontend. Overrides default_view_name."""
226 View to display in the frontend. Overrides default_view_name."""
227
227
228 if not view_name:
228 if not view_name:
229 view_name = self.default_view_name
229 view_name = self.default_view_name
230
230
231 # Create a comm.
231 # Create a comm.
232 if self._comm is None:
232 if self._comm is None:
233 self._comm = Comm(target_name=self.target_name)
233 self._comm = Comm(target_name=self.target_name)
234 self._comm.on_msg(self._handle_msg)
234 self._comm.on_msg(self._handle_msg)
235 self._comm.on_close(self._handle_close)
235 self._comm.on_close(self._handle_close)
236
236
237 # Make sure model is syncronized
237 # Make sure model is syncronized
238 self.send_state()
238 self.send_state()
239
239
240 # Show view.
240 # Show view.
241 if self.parent is None or self.parent._comm is None:
241 if self.parent is None or self.parent._comm is None:
242 self._comm.send({"method": "display", "view_name": view_name})
242 self._comm.send({"method": "display", "view_name": view_name})
243 else:
243 else:
244 self._comm.send({"method": "display",
244 self._comm.send({"method": "display",
245 "view_name": view_name,
245 "view_name": view_name,
246 "parent": self.parent._comm.comm_id})
246 "parent": self.parent._comm.comm_id})
247 self._displayed = True
247 self._displayed = True
248
248
249 # Now display children if any.
249 # Now display children if any.
250 for child in self._children:
250 for child in self._children:
251 if child != self:
251 if child != self:
252 child._repr_widget_()
252 child._repr_widget_()
253 return None
253 return None
General Comments 0
You need to be logged in to leave comments. Login now