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