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