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