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