##// END OF EJS Templates
Added on_view_displayed and on_close callbacks to widget manager.
Jonathan Frederic -
Show More
@@ -1,521 +1,551 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // WidgetModel, WidgetView, and WidgetManager
9 // WidgetModel, WidgetView, and WidgetManager
10 //============================================================================
10 //============================================================================
11 /**
11 /**
12 * Base Widget classes
12 * Base Widget classes
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule widget
15 * @submodule widget
16 */
16 */
17
17
18 "use strict";
18 "use strict";
19
19
20 // Use require.js 'define' method so that require.js is intelligent enough to
20 // Use require.js 'define' method so that require.js is intelligent enough to
21 // syncronously load everything within this file when it is being 'required'
21 // syncronously load everything within this file when it is being 'required'
22 // elsewhere.
22 // elsewhere.
23 define(["components/underscore/underscore-min",
23 define(["components/underscore/underscore-min",
24 "components/backbone/backbone-min",
24 "components/backbone/backbone-min",
25 ], function(underscore, backbone){
25 ], function(underscore, backbone){
26
26
27
27
28 //--------------------------------------------------------------------
28 //--------------------------------------------------------------------
29 // WidgetModel class
29 // WidgetModel class
30 //--------------------------------------------------------------------
30 //--------------------------------------------------------------------
31 var WidgetModel = Backbone.Model.extend({
31 var WidgetModel = Backbone.Model.extend({
32 constructor: function(comm_manager, comm, widget_manager) {
32 constructor: function(comm_manager, comm, widget_manager) {
33 this.comm_manager = comm_manager;
33 this.comm_manager = comm_manager;
34 this.widget_manager = widget_manager;
34 this.widget_manager = widget_manager;
35 this.pending_msgs = 0;
35 this.pending_msgs = 0;
36 this.msg_throttle = 3;
36 this.msg_throttle = 3;
37 this.msg_buffer = null;
37 this.msg_buffer = null;
38 this.views = {};
38 this.views = {};
39
39
40 // Remember comm associated with the model.
40 // Remember comm associated with the model.
41 this.comm = comm;
41 this.comm = comm;
42 comm.model = this;
42 comm.model = this;
43
43
44 // Hook comm messages up to model.
44 // Hook comm messages up to model.
45 comm.on_close($.proxy(this._handle_comm_closed, this));
45 comm.on_close($.proxy(this._handle_comm_closed, this));
46 comm.on_msg($.proxy(this._handle_comm_msg, this));
46 comm.on_msg($.proxy(this._handle_comm_msg, this));
47
47
48 return Backbone.Model.apply(this);
48 return Backbone.Model.apply(this);
49 },
49 },
50
50
51
51
52 update_other_views: function(caller) {
52 update_other_views: function(caller) {
53 this.last_modified_view = caller;
53 this.last_modified_view = caller;
54 this.save(this.changedAttributes(), {patch: true});
54 this.save(this.changedAttributes(), {patch: true});
55
55
56 for (var cell in this.views) {
56 for (var cell in this.views) {
57 var views = this.views[cell];
57 var views = this.views[cell];
58 for (var view_index in views) {
58 for (var view_index in views) {
59 var view = views[view_index];
59 var view = views[view_index];
60 if (view !== caller) {
60 if (view !== caller) {
61 view.update();
61 view.update();
62 }
62 }
63 }
63 }
64 }
64 }
65 },
65 },
66
66
67
67
68 on_view_displayed: function (callback) {
69 this._view_displayed_callback = callback;
70 }
71
72
73 on_close: function (callback) {
74 this._close_callback = callback;
75 }
76
77
68 // Handle when a widget is closed.
78 // Handle when a widget is closed.
69 _handle_comm_closed: function (msg) {
79 _handle_comm_closed: function (msg) {
70 for (var cell in this.views) {
80 for (var cell in this.views) {
71 var views = this.views[cell];
81 var views = this.views[cell];
72 for (var view_index in views) {
82 for (var view_index in views) {
73 var view = views[view_index];
83 var view = views[view_index];
74 view.remove();
84 view.remove();
75 }
85 }
76 }
86 }
77 },
87 },
78
88
79
89
80 // Handle incomming comm msg.
90 // Handle incomming comm msg.
81 _handle_comm_msg: function (msg) {
91 _handle_comm_msg: function (msg) {
82 var method = msg.content.data.method;
92 var method = msg.content.data.method;
83 switch (method){
93 switch (method){
84 case 'display':
94 case 'display':
85
95
86 // Try to get the cell index.
96 // Try to get the cell.
87 var cell = this._get_msg_cell(msg.parent_header.msg_id);
97 var cell = this._get_msg_cell(msg.parent_header.msg_id);
88 if (cell == null) {
98 if (cell == null) {
89 console.log("Could not determine where the display" +
99 console.log("Could not determine where the display" +
90 " message was from. Widget will not be displayed")
100 " message was from. Widget will not be displayed")
91 } else {
101 } else {
92 this._display_view(msg.content.data.view_name,
102 this._display_view(msg.content.data.view_name,
93 msg.content.data.parent,
103 msg.content.data.parent,
94 cell);
104 cell);
95 }
105 }
96 break;
106 break;
97 case 'update':
107 case 'update':
98 this._handle_update(msg.content.data.state);
108 this._handle_update(msg.content.data.state);
99 break;
109 break;
100 }
110 }
101 },
111 },
102
112
103
113
104 // Handle when a widget is updated via the python side.
114 // Handle when a widget is updated via the python side.
105 _handle_update: function (state) {
115 _handle_update: function (state) {
106 this.updating = true;
116 this.updating = true;
107 try {
117 try {
108 for (var key in state) {
118 for (var key in state) {
109 if (state.hasOwnProperty(key)) {
119 if (state.hasOwnProperty(key)) {
110 if (key == "_css"){
120 if (key == "_css"){
111
121
112 // Set the css value of the model as an attribute
122 // Set the css value of the model as an attribute
113 // instead of a backbone trait because we are only
123 // instead of a backbone trait because we are only
114 // interested in backend css -> frontend css. In
124 // interested in backend css -> frontend css. In
115 // other words, if the css dict changes in the
125 // other words, if the css dict changes in the
116 // frontend, we don't need to push the changes to
126 // frontend, we don't need to push the changes to
117 // the backend.
127 // the backend.
118 this.css = state[key];
128 this.css = state[key];
119 } else {
129 } else {
120 this.set(key, state[key]);
130 this.set(key, state[key]);
121 }
131 }
122 }
132 }
123 }
133 }
124 this.id = this.comm.comm_id;
134 this.id = this.comm.comm_id;
125 this.save();
135 this.save();
126 } finally {
136 } finally {
127 this.updating = false;
137 this.updating = false;
128 }
138 }
129 },
139 },
130
140
131
141
132 _handle_status: function (cell, msg) {
142 _handle_status: function (cell, msg) {
133 //execution_state : ('busy', 'idle', 'starting')
143 //execution_state : ('busy', 'idle', 'starting')
134 if (msg.content.execution_state=='idle') {
144 if (msg.content.execution_state=='idle') {
135
145
136 // Send buffer if this message caused another message to be
146 // Send buffer if this message caused another message to be
137 // throttled.
147 // throttled.
138 if (this.msg_buffer != null &&
148 if (this.msg_buffer != null &&
139 this.msg_throttle == this.pending_msgs) {
149 this.msg_throttle == this.pending_msgs) {
140
150
141 var cell = this._get_msg_cell(msg.parent_header.msg_id);
151 var cell = this._get_msg_cell(msg.parent_header.msg_id);
142 var callbacks = this._make_callbacks(cell);
152 var callbacks = this._make_callbacks(cell);
143 var data = {sync_method: 'update', sync_data: this.msg_buffer};
153 var data = {sync_method: 'update', sync_data: this.msg_buffer};
144 this.comm.send(data, callbacks);
154 this.comm.send(data, callbacks);
145 this.msg_buffer = null;
155 this.msg_buffer = null;
146 } else {
156 } else {
147
157
148 // Only decrease the pending message count if the buffer
158 // Only decrease the pending message count if the buffer
149 // doesn't get flushed (sent).
159 // doesn't get flushed (sent).
150 --this.pending_msgs;
160 --this.pending_msgs;
151 }
161 }
152 }
162 }
153 },
163 },
154
164
155
165
156 // Custom syncronization logic.
166 // Custom syncronization logic.
157 _handle_sync: function (method, options) {
167 _handle_sync: function (method, options) {
158 var model_json = this.toJSON();
168 var model_json = this.toJSON();
159
169
160 // Only send updated state if the state hasn't been changed
170 // Only send updated state if the state hasn't been changed
161 // during an update.
171 // during an update.
162 if (!this.updating) {
172 if (!this.updating) {
163 if (this.pending_msgs >= this.msg_throttle) {
173 if (this.pending_msgs >= this.msg_throttle) {
164 // The throttle has been exceeded, buffer the current msg so
174 // The throttle has been exceeded, buffer the current msg so
165 // it can be sent once the kernel has finished processing
175 // it can be sent once the kernel has finished processing
166 // some of the existing messages.
176 // some of the existing messages.
167 if (method=='patch') {
177 if (method=='patch') {
168 if (this.msg_buffer == null) {
178 if (this.msg_buffer == null) {
169 this.msg_buffer = $.extend({}, model_json); // Copy
179 this.msg_buffer = $.extend({}, model_json); // Copy
170 }
180 }
171 for (var attr in options.attrs) {
181 for (var attr in options.attrs) {
172 this.msg_buffer[attr] = options.attrs[attr];
182 this.msg_buffer[attr] = options.attrs[attr];
173 }
183 }
174 } else {
184 } else {
175 this.msg_buffer = $.extend({}, model_json); // Copy
185 this.msg_buffer = $.extend({}, model_json); // Copy
176 }
186 }
177
187
178 } else {
188 } else {
179 // We haven't exceeded the throttle, send the message like
189 // We haven't exceeded the throttle, send the message like
180 // normal. If this is a patch operation, just send the
190 // normal. If this is a patch operation, just send the
181 // changes.
191 // changes.
182 var send_json = model_json;
192 var send_json = model_json;
183 if (method=='patch') {
193 if (method=='patch') {
184 send_json = {};
194 send_json = {};
185 for (var attr in options.attrs) {
195 for (var attr in options.attrs) {
186 send_json[attr] = options.attrs[attr];
196 send_json[attr] = options.attrs[attr];
187 }
197 }
188 }
198 }
189
199
190 var data = {sync_method: method, sync_data: send_json};
200 var data = {sync_method: method, sync_data: send_json};
191
201
192 var cell = null;
202 var cell = null;
193 if (this.last_modified_view != undefined && this.last_modified_view != null) {
203 if (this.last_modified_view != undefined && this.last_modified_view != null) {
194 cell = this.last_modified_view.cell;
204 cell = this.last_modified_view.cell;
195 }
205 }
196
206
197 var callbacks = this._make_callbacks(cell);
207 var callbacks = this._make_callbacks(cell);
198 this.comm.send(data, callbacks);
208 this.comm.send(data, callbacks);
199 this.pending_msgs++;
209 this.pending_msgs++;
200 }
210 }
201 }
211 }
202
212
203 // Since the comm is a one-way communication, assume the message
213 // Since the comm is a one-way communication, assume the message
204 // arrived.
214 // arrived.
205 return model_json;
215 return model_json;
206 },
216 },
207
217
208
218
219 _handle_view_displayed: function(view) {
220 if (this._view_displayed_callback) {
221 try {
222 this._view_displayed_callback(view)
223 } catch (e) {
224 console.log("Exception in widget model view displayed callback", e, view, this);
225 }
226 }
227 }
228
229
209 // Create view that represents the model.
230 // Create view that represents the model.
210 _display_view: function (view_name, parent_comm_id, cell) {
231 _display_view: function (view_name, parent_comm_id, cell) {
211 var new_views = [];
232 var new_views = [];
212
233
213 // Try creating and adding the view to it's parent.
234 // Try creating and adding the view to it's parent.
214 var displayed = false;
235 var displayed = false;
215 if (parent_comm_id != undefined) {
236 if (parent_comm_id != undefined) {
216 var parent_comm = this.comm_manager.comms[parent_comm_id];
237 var parent_comm = this.comm_manager.comms[parent_comm_id];
217 var parent_model = parent_comm.model;
238 var parent_model = parent_comm.model;
218 var parent_views = parent_model.views[cell];
239 var parent_views = parent_model.views[cell];
219 for (var parent_view_index in parent_views) {
240 for (var parent_view_index in parent_views) {
220 var parent_view = parent_views[parent_view_index];
241 var parent_view = parent_views[parent_view_index];
221 if (parent_view.display_child != undefined) {
242 if (parent_view.display_child != undefined) {
222 var view = this._create_view(view_name, cell);
243 var view = this._create_view(view_name, cell);
223 if (view != null) {
244 if (view != null) {
224 new_views.push(view);
245 new_views.push(view);
225 parent_view.display_child(view);
246 parent_view.display_child(view);
226 displayed = true;
247 displayed = true;
248 this._handle_view_displayed(view);
227 }
249 }
228 }
250 }
229 }
251 }
230 }
252 }
231
253
232 // If no parent view is defined or exists. Add the view's
254 // If no parent view is defined or exists. Add the view's
233 // element to cell's widget div.
255 // element to cell's widget div.
234 if (!displayed) {
256 if (!displayed) {
235 var view = this._create_view(view_name, cell);
257 var view = this._create_view(view_name, cell);
236 if (view != null) {
258 if (view != null) {
237 new_views.push(view);
259 new_views.push(view);
238
260
239 if (cell.widget_subarea != undefined && cell.widget_subarea != null) {
261 if (cell.widget_subarea != undefined && cell.widget_subarea != null) {
240 cell.widget_area.show();
262 cell.widget_area.show();
241 cell.widget_subarea.append(view.$el);
263 cell.widget_subarea.append(view.$el);
264 this._handle_view_displayed(view);
242 }
265 }
243 }
266 }
244 }
267 }
245
268
246 // Force the new view(s) to update their selves
269 // Force the new view(s) to update their selves
247 for (var view_index in new_views) {
270 for (var view_index in new_views) {
248 var view = new_views[view_index];
271 var view = new_views[view_index];
249 view.update();
272 view.update();
250 }
273 }
251 },
274 },
252
275
253
276
254 // Create a view
277 // Create a view
255 _create_view: function (view_name, cell) {
278 _create_view: function (view_name, cell) {
256 var view_type = this.widget_manager.widget_view_types[view_name];
279 var view_type = this.widget_manager.widget_view_types[view_name];
257 if (view_type != undefined && view_type != null) {
280 if (view_type != undefined && view_type != null) {
258 var view = new view_type({model: this});
281 var view = new view_type({model: this});
259 view.render();
282 view.render();
260 if (this.views[cell]==undefined) {
283 if (this.views[cell]==undefined) {
261 this.views[cell] = []
284 this.views[cell] = []
262 }
285 }
263 this.views[cell].push(view);
286 this.views[cell].push(view);
264 view.cell = cell;
287 view.cell = cell;
265
288
266 // Handle when the view element is remove from the page.
289 // Handle when the view element is remove from the page.
267 var that = this;
290 var that = this;
268 view.$el.on("remove", function(){
291 view.$el.on("remove", function(){
269 var index = that.views[cell].indexOf(view);
292 var index = that.views[cell].indexOf(view);
270 if (index > -1) {
293 if (index > -1) {
271 that.views[cell].splice(index, 1);
294 that.views[cell].splice(index, 1);
272 }
295 }
273 view.remove(); // Clean-up view
296 view.remove(); // Clean-up view
274 if (that.views[cell].length()==0) {
297 if (that.views[cell].length()==0) {
275 delete that.views[cell];
298 delete that.views[cell];
276 }
299 }
277
300
278 // Close the comm if there are no views left.
301 // Close the comm if there are no views left.
279 if (that.views.length()==0) {
302 if (that.views.length()==0) {
303 if (that._close_callback) {
304 try {
305 that._close_callback(that)
306 } catch (e) {
307 console.log("Exception in widget model close callback", e, that);
308 }
309 }
280 that.comm.close();
310 that.comm.close();
281 }
311 }
282 });
312 });
283 return view;
313 return view;
284 }
314 }
285 return null;
315 return null;
286 },
316 },
287
317
288
318
289 // Build a callback dict.
319 // Build a callback dict.
290 _make_callbacks: function (cell) {
320 _make_callbacks: function (cell) {
291 var callbacks = {};
321 var callbacks = {};
292 if (cell != null && cell.output_area != undefined && cell.output_area != null) {
322 if (cell != null && cell.output_area != undefined && cell.output_area != null) {
293 var that = this;
323 var that = this;
294 callbacks = {
324 callbacks = {
295 iopub : {
325 iopub : {
296 output : $.proxy(cell.output_area.handle_output, cell.output_area),
326 output : $.proxy(cell.output_area.handle_output, cell.output_area),
297 clear_output : $.proxy(cell.output_area.handle_clear_output, cell.output_area),
327 clear_output : $.proxy(cell.output_area.handle_clear_output, cell.output_area),
298 status : function(msg){
328 status : function(msg){
299 that._handle_status(cell, msg);
329 that._handle_status(cell, msg);
300 },
330 },
301
331
302 // Special function only registered by widget messages.
332 // Special function only registered by widget messages.
303 // Allows us to get the cell for a message so we know
333 // Allows us to get the cell for a message so we know
304 // where to add widgets if the code requires it.
334 // where to add widgets if the code requires it.
305 get_cell : function() {
335 get_cell : function() {
306 if (that.last_modified_view != undefined &&
336 if (that.last_modified_view != undefined &&
307 that.last_modified_view.cell != undefined) {
337 that.last_modified_view.cell != undefined) {
308 return that.last_modified_view.cell;
338 return that.last_modified_view.cell;
309 } else {
339 } else {
310 return null
340 return null
311 }
341 }
312 },
342 },
313 },
343 },
314 };
344 };
315 }
345 }
316 return callbacks;
346 return callbacks;
317 },
347 },
318
348
319
349
320 // Get the output area corresponding to the msg_id.
350 // Get the output area corresponding to the msg_id.
321 // cell is an instance of IPython.Cell
351 // cell is an instance of IPython.Cell
322 _get_msg_cell: function (msg_id) {
352 _get_msg_cell: function (msg_id) {
323
353
324 // First, check to see if the msg was triggered by cell execution.
354 // First, check to see if the msg was triggered by cell execution.
325 var cell = this.widget_manager.get_msg_cell(msg_id);
355 var cell = this.widget_manager.get_msg_cell(msg_id);
326 if (cell != null) {
356 if (cell != null) {
327 return cell;
357 return cell;
328 }
358 }
329
359
330 // Second, check to see if a get_cell callback was defined
360 // Second, check to see if a get_cell callback was defined
331 // for the message. get_cell callbacks are registered for
361 // for the message. get_cell callbacks are registered for
332 // widget messages, so this block is actually checking to see if the
362 // widget messages, so this block is actually checking to see if the
333 // message was triggered by a widget.
363 // message was triggered by a widget.
334 var kernel = this.comm_manager.kernel;
364 var kernel = this.comm_manager.kernel;
335 var callbacks = kernel.get_callbacks_for_msg(msg_id);
365 var callbacks = kernel.get_callbacks_for_msg(msg_id);
336 if (callbacks != undefined &&
366 if (callbacks != undefined &&
337 callbacks.iopub != undefined &&
367 callbacks.iopub != undefined &&
338 callbacks.iopub.get_cell != undefined) {
368 callbacks.iopub.get_cell != undefined) {
339
369
340 return callbacks.iopub.get_cell();
370 return callbacks.iopub.get_cell();
341 }
371 }
342
372
343 // Not triggered by a cell or widget (no get_cell callback
373 // Not triggered by a cell or widget (no get_cell callback
344 // exists).
374 // exists).
345 return null;
375 return null;
346 },
376 },
347
377
348 });
378 });
349
379
350
380
351 //--------------------------------------------------------------------
381 //--------------------------------------------------------------------
352 // WidgetView class
382 // WidgetView class
353 //--------------------------------------------------------------------
383 //--------------------------------------------------------------------
354 var WidgetView = Backbone.View.extend({
384 var WidgetView = Backbone.View.extend({
355
385
356 initialize: function() {
386 initialize: function() {
357 this.visible = true;
387 this.visible = true;
358 this.model.on('change',this.update,this);
388 this.model.on('change',this.update,this);
359 this._add_class_calls = this.model.get('_add_class')[0];
389 this._add_class_calls = this.model.get('_add_class')[0];
360 this._remove_class_calls = this.model.get('_remove_class')[0];
390 this._remove_class_calls = this.model.get('_remove_class')[0];
361 },
391 },
362
392
363 update: function() {
393 update: function() {
364 if (this.model.get('visible') != undefined) {
394 if (this.model.get('visible') != undefined) {
365 if (this.visible != this.model.get('visible')) {
395 if (this.visible != this.model.get('visible')) {
366 this.visible = this.model.get('visible');
396 this.visible = this.model.get('visible');
367 if (this.visible) {
397 if (this.visible) {
368 this.$el.show();
398 this.$el.show();
369 } else {
399 } else {
370 this.$el.hide();
400 this.$el.hide();
371 }
401 }
372 }
402 }
373 }
403 }
374
404
375 if (this.model.css != undefined) {
405 if (this.model.css != undefined) {
376 for (var selector in this.model.css) {
406 for (var selector in this.model.css) {
377 if (this.model.css.hasOwnProperty(selector)) {
407 if (this.model.css.hasOwnProperty(selector)) {
378
408
379 // Apply the css traits to all elements that match the selector.
409 // Apply the css traits to all elements that match the selector.
380 var elements = this._get_selector_element(selector);
410 var elements = this._get_selector_element(selector);
381 if (elements.length > 0) {
411 if (elements.length > 0) {
382 var css_traits = this.model.css[selector];
412 var css_traits = this.model.css[selector];
383 for (var css_key in css_traits) {
413 for (var css_key in css_traits) {
384 if (css_traits.hasOwnProperty(css_key)) {
414 if (css_traits.hasOwnProperty(css_key)) {
385 elements.css(css_key, css_traits[css_key]);
415 elements.css(css_key, css_traits[css_key]);
386 }
416 }
387 }
417 }
388 }
418 }
389 }
419 }
390 }
420 }
391 }
421 }
392
422
393 var add_class = this.model.get('_add_class');
423 var add_class = this.model.get('_add_class');
394 if (add_class != undefined){
424 if (add_class != undefined){
395 var add_class_calls = add_class[0];
425 var add_class_calls = add_class[0];
396 if (add_class_calls > this._add_class_calls) {
426 if (add_class_calls > this._add_class_calls) {
397 this._add_class_calls = add_class_calls;
427 this._add_class_calls = add_class_calls;
398 var elements = this._get_selector_element(add_class[1]);
428 var elements = this._get_selector_element(add_class[1]);
399 if (elements.length > 0) {
429 if (elements.length > 0) {
400 elements.addClass(add_class[2]);
430 elements.addClass(add_class[2]);
401 }
431 }
402 }
432 }
403 }
433 }
404
434
405 var remove_class = this.model.get('_remove_class');
435 var remove_class = this.model.get('_remove_class');
406 if (remove_class != undefined){
436 if (remove_class != undefined){
407 var remove_class_calls = remove_class[0];
437 var remove_class_calls = remove_class[0];
408 if (remove_class_calls > this._remove_class_calls) {
438 if (remove_class_calls > this._remove_class_calls) {
409 this._remove_class_calls = remove_class_calls;
439 this._remove_class_calls = remove_class_calls;
410 var elements = this._get_selector_element(remove_class[1]);
440 var elements = this._get_selector_element(remove_class[1]);
411 if (elements.length > 0) {
441 if (elements.length > 0) {
412 elements.removeClass(remove_class[2]);
442 elements.removeClass(remove_class[2]);
413 }
443 }
414 }
444 }
415 }
445 }
416 },
446 },
417
447
418 _get_selector_element: function(selector) {
448 _get_selector_element: function(selector) {
419 // Get the elements via the css selector. If the selector is
449 // Get the elements via the css selector. If the selector is
420 // blank, apply the style to the $el_to_style element. If
450 // blank, apply the style to the $el_to_style element. If
421 // the $el_to_style element is not defined, use apply the
451 // the $el_to_style element is not defined, use apply the
422 // style to the view's element.
452 // style to the view's element.
423 var elements = this.$el.find(selector);
453 var elements = this.$el.find(selector);
424 if (selector=='') {
454 if (selector=='') {
425 if (this.$el_to_style == undefined) {
455 if (this.$el_to_style == undefined) {
426 elements = this.$el;
456 elements = this.$el;
427 } else {
457 } else {
428 elements = this.$el_to_style;
458 elements = this.$el_to_style;
429 }
459 }
430 }
460 }
431 return elements;
461 return elements;
432 },
462 },
433 });
463 });
434
464
435
465
436 //--------------------------------------------------------------------
466 //--------------------------------------------------------------------
437 // WidgetManager class
467 // WidgetManager class
438 //--------------------------------------------------------------------
468 //--------------------------------------------------------------------
439 var WidgetManager = function(){
469 var WidgetManager = function(){
440 this.comm_manager = null;
470 this.comm_manager = null;
441 this.widget_model_types = {};
471 this.widget_model_types = {};
442 this.widget_view_types = {};
472 this.widget_view_types = {};
443
473
444 var that = this;
474 var that = this;
445 Backbone.sync = function(method, model, options, error) {
475 Backbone.sync = function(method, model, options, error) {
446 var result = model._handle_sync(method, options);
476 var result = model._handle_sync(method, options);
447 if (options.success) {
477 if (options.success) {
448 options.success(result);
478 options.success(result);
449 }
479 }
450 };
480 };
451 }
481 }
452
482
453
483
454 WidgetManager.prototype.attach_comm_manager = function (comm_manager) {
484 WidgetManager.prototype.attach_comm_manager = function (comm_manager) {
455 this.comm_manager = comm_manager;
485 this.comm_manager = comm_manager;
456
486
457 // Register already register widget model types with the comm manager.
487 // Register already register widget model types with the comm manager.
458 for (var widget_model_name in this.widget_model_types) {
488 for (var widget_model_name in this.widget_model_types) {
459 this.comm_manager.register_target(widget_model_name, $.proxy(this._handle_com_open, this));
489 this.comm_manager.register_target(widget_model_name, $.proxy(this._handle_com_open, this));
460 }
490 }
461 }
491 }
462
492
463
493
464 WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {
494 WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {
465 // Register the widget with the comm manager. Make sure to pass this object's context
495 // Register the widget with the comm manager. Make sure to pass this object's context
466 // in so `this` works in the call back.
496 // in so `this` works in the call back.
467 if (this.comm_manager!=null) {
497 if (this.comm_manager!=null) {
468 this.comm_manager.register_target(widget_model_name, $.proxy(this._handle_com_open, this));
498 this.comm_manager.register_target(widget_model_name, $.proxy(this._handle_com_open, this));
469 }
499 }
470 this.widget_model_types[widget_model_name] = widget_model_type;
500 this.widget_model_types[widget_model_name] = widget_model_type;
471 }
501 }
472
502
473
503
474 WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
504 WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
475 this.widget_view_types[widget_view_name] = widget_view_type;
505 this.widget_view_types[widget_view_name] = widget_view_type;
476 }
506 }
477
507
478
508
479 WidgetManager.prototype.get_msg_cell = function (msg_id) {
509 WidgetManager.prototype.get_msg_cell = function (msg_id) {
480 if (IPython.notebook != undefined && IPython.notebook != null) {
510 if (IPython.notebook != undefined && IPython.notebook != null) {
481 return IPython.notebook.get_msg_cell(msg_id);
511 return IPython.notebook.get_msg_cell(msg_id);
482 }
512 }
483 }
513 }
484
514
485
515
486 WidgetManager.prototype.on_create_widget = function (callback) {
516 WidgetManager.prototype.on_create_widget = function (callback) {
487 this._create_widget_callback = callback;
517 this._create_widget_callback = callback;
488 }
518 }
489
519
490
520
491 WidgetManager.prototype._handle_create_widget = function (widget_model) {
521 WidgetManager.prototype._handle_create_widget = function (widget_model) {
492 if (this._create_widget_callback) {
522 if (this._create_widget_callback) {
493 try {
523 try {
494 this._create_widget_callback(widget_model);
524 this._create_widget_callback(widget_model);
495 } catch (e) {
525 } catch (e) {
496 console.log("Exception in WidgetManager callback", e, widget_model);
526 console.log("Exception in WidgetManager callback", e, widget_model);
497 }
527 }
498 }
528 }
499 }
529 }
500
530
501
531
502 WidgetManager.prototype._handle_com_open = function (comm, msg) {
532 WidgetManager.prototype._handle_com_open = function (comm, msg) {
503 var widget_type_name = msg.content.target_name;
533 var widget_type_name = msg.content.target_name;
504 var widget_model = new this.widget_model_types[widget_type_name](this.comm_manager, comm, this);
534 var widget_model = new this.widget_model_types[widget_type_name](this.comm_manager, comm, this);
505 this._handle_create_widget(widget_model);
535 this._handle_create_widget(widget_model);
506 }
536 }
507
537
508
538
509 //--------------------------------------------------------------------
539 //--------------------------------------------------------------------
510 // Init code
540 // Init code
511 //--------------------------------------------------------------------
541 //--------------------------------------------------------------------
512 IPython.WidgetManager = WidgetManager;
542 IPython.WidgetManager = WidgetManager;
513 IPython.WidgetModel = WidgetModel;
543 IPython.WidgetModel = WidgetModel;
514 IPython.WidgetView = WidgetView;
544 IPython.WidgetView = WidgetView;
515
545
516 if (IPython.widget_manager==undefined || IPython.widget_manager==null) {
546 if (IPython.widget_manager==undefined || IPython.widget_manager==null) {
517 IPython.widget_manager = new WidgetManager();
547 IPython.widget_manager = new WidgetManager();
518 }
548 }
519
549
520 return IPython.widget_manager;
550 return IPython.widget_manager;
521 });
551 });
General Comments 0
You need to be logged in to leave comments. Login now