##// END OF EJS Templates
Changed js loading,...
Jonathan Frederic -
Show More
@@ -1,7 +1,7 b''
1 from base import Widget
1 from base import Widget, init_widget_js
2 2
3 3 from container import ContainerWidget
4 4 from float_range import FloatRangeWidget
5 5 from int_range import IntRangeWidget
6 6 from selection import SelectionWidget
7 7 from string import StringWidget
@@ -1,168 +1,164 b''
1 1 from copy import copy
2 2 from glob import glob
3 3 import uuid
4 4 import sys
5 5 import os
6 6
7 7 import IPython
8 8 from IPython.kernel.comm import Comm
9 9 from IPython.config import LoggingConfigurable
10 10 from IPython.utils.traitlets import Unicode, Dict, List
11 11 from IPython.display import Javascript, display
12 12 from IPython.utils.py3compat import string_types
13 13
14 def init_widget_js():
15 path = os.path.split(os.path.abspath( __file__ ))[0]
16 for filepath in glob(os.path.join(path, "*.py")):
17 filename = os.path.split(filepath)[1]
18 name = filename.rsplit('.', 1)[0]
19 if not (name == 'base' or name == '__init__'):
20 js_path = 'static/notebook/js/widgets/%s.js' % name
21 display(Javascript(data='$.getScript("%s");' % js_path))
22
14 23
15 24 class Widget(LoggingConfigurable):
16 25
17 26 ### Public declarations
18 27 target_name = Unicode('widget')
19 28 default_view_name = Unicode()
20 js_requirements = List()
21 29
22 30
23 31 ### Private/protected declarations
24 32 _keys = []
25 33 _property_lock = False
26 34 _parent = None
27 35 _children = []
28 36 _css = Dict()
29 37
30 38
31 39 ### Public constructor
32 40 def __init__(self, parent=None, **kwargs):
33 41 super(Widget, self).__init__(**kwargs)
34 42
35 43 self._children = []
36 44 if parent is not None:
37 45 parent._children.append(self)
38 46 self._parent = parent
39 47 self.comm = None
40 48
41 49 # Register after init to allow default values to be specified
42 50 self.on_trait_change(self._handle_property_changed, self.keys)
43 51
44 52
45 53 def __del__(self):
46 54 self.close()
47 55
48 56 def close(self):
49 57 self.comm.close()
50 58 del self.comm
51 59
52 60
53 61 ### Properties
54 62 def _get_parent(self):
55 63 return self._parent
56 64 parent = property(_get_parent)
57 65
58 66
59 67 def _get_children(self):
60 68 return copy(self._children)
61 69 children = property(_get_children)
62 70
63 71
64 72 def _get_keys(self):
65 73 keys = ['_css']
66 74 keys.extend(self._keys)
67 75 return keys
68 76 keys = property(_get_keys)
69 77
70 78 def _get_css(self, key, selector=""):
71 79 if selector in self._css and key in self._css[selector]:
72 80 return self._css[selector][key]
73 81 else:
74 82 return None
75 83 def _set_css(self, value, key, selector=""):
76 84 if selector not in self._css:
77 85 self._css[selector] = {}
78 86
79 87 # Only update the property if it has changed.
80 88 if not (key in self._css[selector] and value in self._css[selector][key]):
81 89 self._css[selector][key] = value
82 90 self.send_state() # Send new state to client.
83 91
84 92 css = property(_get_css, _set_css)
85 93
86 94
87 95 ### Event handlers
88 96 def _handle_msg(self, msg):
89 97
90 98 # Handle backbone sync methods
91 99 sync_method = msg['content']['data']['sync_method']
92 100 sync_data = msg['content']['data']['sync_data']
93 101 if sync_method.lower() in ['create', 'update']:
94 102 self._handle_recieve_state(sync_data)
95 103
96 104
97 105 def _handle_recieve_state(self, sync_data):
98 106 self._property_lock = True
99 107 try:
100 108
101 109 # Use _keys instead of keys - Don't get retrieve the css from the client side.
102 110 for name in self._keys:
103 111 if name in sync_data:
104 112 setattr(self, name, sync_data[name])
105 113 finally:
106 114 self._property_lock = False
107 115
108 116
109 117 def _handle_property_changed(self, name, old, new):
110 118 if not self._property_lock and self.comm is not None:
111 119 # TODO: Validate properties.
112 120 # Send new state to frontend
113 121 self.send_state()
114 122
115 123
116 124 def _handle_close(self):
117 125 self.comm = None
118 126
119 127
120 128 ### Public methods
121 129 def _repr_widget_(self, view_name=None):
122 130 if not view_name:
123 131 view_name = self.default_view_name
124 132
125 # Require traitlet specified widget js
126 self._require_js('static/notebook/js/widget.js')
127 for requirement in self.js_requirements:
128 self._require_js(requirement)
129
130 133 # Create a comm.
131 134 if self.comm is None:
132 135 self.comm = Comm(target_name=self.target_name)
133 136 self.comm.on_msg(self._handle_msg)
134 137 self.comm.on_close(self._handle_close)
135 138
136 139 # Make sure model is syncronized
137 140 self.send_state()
138 141
139 142 # Show view.
140 143 if self.parent is None:
141 144 self.comm.send({"method": "show", "view_name": view_name})
142 145 else:
143 146 self.comm.send({"method": "show",
144 147 "view_name": view_name,
145 148 "parent": self.parent.comm.comm_id})
146 149
147 150 # Now show children if any.
148 151 for child in self.children:
149 152 child._repr_widget_()
150 153 return None
151 154
152 155
153 156 def send_state(self):
154 157 state = {}
155 158 for key in self.keys:
156 159 try:
157 160 state[key] = getattr(self, key)
158 161 except Exception as e:
159 162 pass # Eat errors, nom nom nom
160 163 self.comm.send({"method": "update",
161 164 "state": state})
162
163 ### Private methods
164
165 def _require_js(self, js_path):
166 # Since we are loading requirements that must be loaded before this call
167 # returns, preform async js load.
168 display(Javascript(data='$.ajax({url: "%s", async: false, dataType: "script", timeout: 1000});' % js_path))
General Comments 0
You need to be logged in to leave comments. Login now