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