Show More
@@ -1,460 +1,439 | |||||
1 | //---------------------------------------------------------------------------- |
|
1 | //---------------------------------------------------------------------------- | |
2 | // Copyright (C) 2008-2011 The IPython Development Team |
|
2 | // Copyright (C) 2008-2011 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 | // Kernel |
|
9 | // Kernel | |
10 | //============================================================================ |
|
10 | //============================================================================ | |
11 |
|
11 | |||
12 | /** |
|
12 | /** | |
13 | * @module IPython |
|
13 | * @module IPython | |
14 | * @namespace IPython |
|
14 | * @namespace IPython | |
15 | * @submodule Kernel |
|
15 | * @submodule Kernel | |
16 | */ |
|
16 | */ | |
17 |
|
17 | |||
18 | var IPython = (function (IPython) { |
|
18 | var IPython = (function (IPython) { | |
19 |
|
19 | |||
20 | var utils = IPython.utils; |
|
20 | var utils = IPython.utils; | |
21 |
|
21 | |||
22 | // Initialization and connection. |
|
22 | // Initialization and connection. | |
23 | /** |
|
23 | /** | |
24 | * A Kernel Class to communicate with the Python kernel |
|
24 | * A Kernel Class to communicate with the Python kernel | |
25 | * @Class Kernel |
|
25 | * @Class Kernel | |
26 | */ |
|
26 | */ | |
27 | var Kernel = function (base_url) { |
|
27 | var Kernel = function (base_url) { | |
28 | this.kernel_id = null; |
|
28 | this.kernel_id = null; | |
29 | this.shell_channel = null; |
|
29 | this.shell_channel = null; | |
30 | this.iopub_channel = null; |
|
30 | this.iopub_channel = null; | |
31 | this.base_url = base_url; |
|
31 | this.base_url = base_url; | |
32 | this.running = false; |
|
32 | this.running = false; | |
33 | this.username = "username"; |
|
33 | this.username = "username"; | |
34 | this.session_id = utils.uuid(); |
|
34 | this.session_id = utils.uuid(); | |
35 | this._msg_callbacks = {}; |
|
35 | this._msg_callbacks = {}; | |
36 |
|
36 | |||
37 | if (typeof(WebSocket) !== 'undefined') { |
|
37 | if (typeof(WebSocket) !== 'undefined') { | |
38 | this.WebSocket = WebSocket; |
|
38 | this.WebSocket = WebSocket; | |
39 | } else if (typeof(MozWebSocket) !== 'undefined') { |
|
39 | } else if (typeof(MozWebSocket) !== 'undefined') { | |
40 | this.WebSocket = MozWebSocket; |
|
40 | this.WebSocket = MozWebSocket; | |
41 | } else { |
|
41 | } else { | |
42 | alert('Your browser does not have WebSocket support, please try Chrome, Safari or Firefox ≥ 6. Firefox 4 and 5 are also supported by you have to enable WebSockets in about:config.'); |
|
42 | alert('Your browser does not have WebSocket support, please try Chrome, Safari or Firefox ≥ 6. Firefox 4 and 5 are also supported by you have to enable WebSockets in about:config.'); | |
43 | }; |
|
43 | }; | |
44 | }; |
|
44 | }; | |
45 |
|
45 | |||
46 |
|
46 | |||
47 | Kernel.prototype._get_msg = function (msg_type, content) { |
|
47 | Kernel.prototype._get_msg = function (msg_type, content) { | |
48 | var msg = { |
|
48 | var msg = { | |
49 | header : { |
|
49 | header : { | |
50 | msg_id : utils.uuid(), |
|
50 | msg_id : utils.uuid(), | |
51 | username : this.username, |
|
51 | username : this.username, | |
52 | session : this.session_id, |
|
52 | session : this.session_id, | |
53 | msg_type : msg_type |
|
53 | msg_type : msg_type | |
54 | }, |
|
54 | }, | |
55 | metadata : {}, |
|
55 | metadata : {}, | |
56 | content : content, |
|
56 | content : content, | |
57 | parent_header : {} |
|
57 | parent_header : {} | |
58 | }; |
|
58 | }; | |
59 | return msg; |
|
59 | return msg; | |
60 | }; |
|
60 | }; | |
61 |
|
61 | |||
62 | /** |
|
62 | /** | |
63 | * Start the Python kernel |
|
63 | * Start the Python kernel | |
64 | * @method start |
|
64 | * @method start | |
65 | */ |
|
65 | */ | |
66 | Kernel.prototype.start = function (notebook_id) { |
|
66 | Kernel.prototype.start = function (notebook_id) { | |
67 | var that = this; |
|
67 | var that = this; | |
68 | if (!this.running) { |
|
68 | if (!this.running) { | |
69 | var qs = $.param({notebook:notebook_id}); |
|
69 | var qs = $.param({notebook:notebook_id}); | |
70 | var url = this.base_url + '?' + qs; |
|
70 | var url = this.base_url + '?' + qs; | |
71 | $.post(url, |
|
71 | $.post(url, | |
72 | $.proxy(that._kernel_started,that), |
|
72 | $.proxy(that._kernel_started,that), | |
73 | 'json' |
|
73 | 'json' | |
74 | ); |
|
74 | ); | |
75 | }; |
|
75 | }; | |
76 | }; |
|
76 | }; | |
77 |
|
77 | |||
78 | /** |
|
78 | /** | |
79 | * Restart the python kernel. |
|
79 | * Restart the python kernel. | |
80 | * |
|
80 | * | |
81 | * Emit a 'status_restarting.Kernel' event with |
|
81 | * Emit a 'status_restarting.Kernel' event with | |
82 | * the current object as parameter |
|
82 | * the current object as parameter | |
83 | * |
|
83 | * | |
84 | * @method restart |
|
84 | * @method restart | |
85 | */ |
|
85 | */ | |
86 | Kernel.prototype.restart = function () { |
|
86 | Kernel.prototype.restart = function () { | |
87 | $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this}); |
|
87 | $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this}); | |
88 | var that = this; |
|
88 | var that = this; | |
89 | if (this.running) { |
|
89 | if (this.running) { | |
90 | this.stop_channels(); |
|
90 | this.stop_channels(); | |
91 | var url = this.kernel_url + "/restart"; |
|
91 | var url = this.kernel_url + "/restart"; | |
92 | $.post(url, |
|
92 | $.post(url, | |
93 | $.proxy(that._kernel_started, that), |
|
93 | $.proxy(that._kernel_started, that), | |
94 | 'json' |
|
94 | 'json' | |
95 | ); |
|
95 | ); | |
96 | }; |
|
96 | }; | |
97 | }; |
|
97 | }; | |
98 |
|
98 | |||
99 |
|
99 | |||
100 | Kernel.prototype._kernel_started = function (json) { |
|
100 | Kernel.prototype._kernel_started = function (json) { | |
101 | console.log("Kernel started: ", json.kernel_id); |
|
101 | console.log("Kernel started: ", json.kernel_id); | |
102 | this.running = true; |
|
102 | this.running = true; | |
103 | this.kernel_id = json.kernel_id; |
|
103 | this.kernel_id = json.kernel_id; | |
104 | this.ws_url = json.ws_url; |
|
104 | this.ws_url = json.ws_url; | |
105 | this.kernel_url = this.base_url + "/" + this.kernel_id; |
|
105 | this.kernel_url = this.base_url + "/" + this.kernel_id; | |
106 | this.start_channels(); |
|
106 | this.start_channels(); | |
107 | this.shell_channel.onmessage = $.proxy(this._handle_shell_reply,this); |
|
107 | this.shell_channel.onmessage = $.proxy(this._handle_shell_reply,this); | |
108 | this.iopub_channel.onmessage = $.proxy(this._handle_iopub_reply,this); |
|
108 | this.iopub_channel.onmessage = $.proxy(this._handle_iopub_reply,this); | |
109 | $([IPython.events]).trigger('status_started.Kernel', {kernel: this}); |
|
109 | $([IPython.events]).trigger('status_started.Kernel', {kernel: this}); | |
110 | }; |
|
110 | }; | |
111 |
|
111 | |||
112 |
|
112 | |||
113 | Kernel.prototype._websocket_closed = function(ws_url, early){ |
|
113 | Kernel.prototype._websocket_closed = function(ws_url, early) { | |
114 | var msg; |
|
114 | this.stop_channels(); | |
115 | var parent_item = $('body'); |
|
115 | $([IPython.events]).trigger('websocket_closed.Kernel', | |
116 | if (early) { |
|
116 | {ws_url: ws_url, kernel: this, early: early} | |
117 | msg = "Websocket connection to " + ws_url + " could not be established." + |
|
117 | ); | |
118 | " You will NOT be able to run code." + |
|
|||
119 | " Your browser may not be compatible with the websocket version in the server," + |
|
|||
120 | " or if the url does not look right, there could be an error in the" + |
|
|||
121 | " server's configuration."; |
|
|||
122 | } else { |
|
|||
123 | IPython.notification_area.widget('kernel').set_message('Reconnecting Websockets', 1000); |
|
|||
124 | this.start_channels(); |
|
|||
125 | return; |
|
|||
126 | } |
|
|||
127 | var dialog = $('<div/>'); |
|
|||
128 | dialog.html(msg); |
|
|||
129 | parent_item.append(dialog); |
|
|||
130 | dialog.dialog({ |
|
|||
131 | resizable: false, |
|
|||
132 | modal: true, |
|
|||
133 | title: "Websocket closed", |
|
|||
134 | closeText: "", |
|
|||
135 | close: function(event, ui) {$(this).dialog('destroy').remove();}, |
|
|||
136 | buttons : { |
|
|||
137 | "OK": function () { |
|
|||
138 | $(this).dialog('close'); |
|
|||
139 | } |
|
|||
140 | } |
|
|||
141 | }); |
|
|||
142 |
|
||||
143 | }; |
|
118 | }; | |
144 |
|
119 | |||
145 | /** |
|
120 | /** | |
146 | * Start the `shell`and `iopub` channels. |
|
121 | * Start the `shell`and `iopub` channels. | |
147 | * Will stop and restart them if they already exist. |
|
122 | * Will stop and restart them if they already exist. | |
148 | * |
|
123 | * | |
149 | * @method start_channels |
|
124 | * @method start_channels | |
150 | */ |
|
125 | */ | |
151 | Kernel.prototype.start_channels = function () { |
|
126 | Kernel.prototype.start_channels = function () { | |
152 | var that = this; |
|
127 | var that = this; | |
153 | this.stop_channels(); |
|
128 | this.stop_channels(); | |
154 | var ws_url = this.ws_url + this.kernel_url; |
|
129 | var ws_url = this.ws_url + this.kernel_url; | |
155 | console.log("Starting WS:", ws_url); |
|
130 | console.log("Starting WebSockets:", ws_url); | |
156 | this.shell_channel = new this.WebSocket(ws_url + "/shell"); |
|
131 | this.shell_channel = new this.WebSocket(ws_url + "/shell"); | |
157 | this.iopub_channel = new this.WebSocket(ws_url + "/iopub"); |
|
132 | this.iopub_channel = new this.WebSocket(ws_url + "/iopub"); | |
158 | send_cookie = function(){ |
|
133 | send_cookie = function(){ | |
159 | this.send(document.cookie); |
|
134 | this.send(document.cookie); | |
160 | }; |
|
135 | }; | |
161 | var already_called_onclose = false; // only alert once |
|
136 | var already_called_onclose = false; // only alert once | |
162 | var ws_closed_early = function(evt){ |
|
137 | var ws_closed_early = function(evt){ | |
163 | if (already_called_onclose){ |
|
138 | if (already_called_onclose){ | |
164 | return; |
|
139 | return; | |
165 | } |
|
140 | } | |
166 | already_called_onclose = true; |
|
141 | already_called_onclose = true; | |
167 | if ( ! evt.wasClean ){ |
|
142 | if ( ! evt.wasClean ){ | |
168 | that._websocket_closed(ws_url, true); |
|
143 | that._websocket_closed(ws_url, true); | |
169 | } |
|
144 | } | |
170 | }; |
|
145 | }; | |
171 | var ws_closed_late = function(evt){ |
|
146 | var ws_closed_late = function(evt){ | |
172 | if (already_called_onclose){ |
|
147 | if (already_called_onclose){ | |
173 | return; |
|
148 | return; | |
174 | } |
|
149 | } | |
175 | already_called_onclose = true; |
|
150 | already_called_onclose = true; | |
176 | if ( ! evt.wasClean ){ |
|
151 | if ( ! evt.wasClean ){ | |
177 | that._websocket_closed(ws_url, false); |
|
152 | that._websocket_closed(ws_url, false); | |
178 | } |
|
153 | } | |
179 | }; |
|
154 | }; | |
180 | this.shell_channel.onopen = send_cookie; |
|
155 | this.shell_channel.onopen = send_cookie; | |
181 | this.shell_channel.onclose = ws_closed_early; |
|
156 | this.shell_channel.onclose = ws_closed_early; | |
182 | this.iopub_channel.onopen = send_cookie; |
|
157 | this.iopub_channel.onopen = send_cookie; | |
183 | this.iopub_channel.onclose = ws_closed_early; |
|
158 | this.iopub_channel.onclose = ws_closed_early; | |
184 | // switch from early-close to late-close message after 1s |
|
159 | // switch from early-close to late-close message after 1s | |
185 | setTimeout(function(){ |
|
160 | setTimeout(function() { | |
186 |
that.shell_channel |
|
161 | if (that.shell_channel !== null) { | |
187 |
that. |
|
162 | that.shell_channel.onclose = ws_closed_late; | |
|
163 | } | |||
|
164 | if (that.iopub_channel !== null) { | |||
|
165 | that.iopub_channel.onclose = ws_closed_late; | |||
|
166 | } | |||
188 | }, 1000); |
|
167 | }, 1000); | |
189 | }; |
|
168 | }; | |
190 |
|
169 | |||
191 | /** |
|
170 | /** | |
192 | * Start the `shell`and `iopub` channels. |
|
171 | * Start the `shell`and `iopub` channels. | |
193 | * @method stop_channels |
|
172 | * @method stop_channels | |
194 | */ |
|
173 | */ | |
195 | Kernel.prototype.stop_channels = function () { |
|
174 | Kernel.prototype.stop_channels = function () { | |
196 | if (this.shell_channel !== null) { |
|
175 | if (this.shell_channel !== null) { | |
197 | this.shell_channel.onclose = function (evt) {}; |
|
176 | this.shell_channel.onclose = function (evt) {}; | |
198 | this.shell_channel.close(); |
|
177 | this.shell_channel.close(); | |
199 | this.shell_channel = null; |
|
178 | this.shell_channel = null; | |
200 | }; |
|
179 | }; | |
201 | if (this.iopub_channel !== null) { |
|
180 | if (this.iopub_channel !== null) { | |
202 | this.iopub_channel.onclose = function (evt) {}; |
|
181 | this.iopub_channel.onclose = function (evt) {}; | |
203 | this.iopub_channel.close(); |
|
182 | this.iopub_channel.close(); | |
204 | this.iopub_channel = null; |
|
183 | this.iopub_channel = null; | |
205 | }; |
|
184 | }; | |
206 | }; |
|
185 | }; | |
207 |
|
186 | |||
208 | // Main public methods. |
|
187 | // Main public methods. | |
209 |
|
188 | |||
210 | /** |
|
189 | /** | |
211 | * Get info on object asynchronoulsy |
|
190 | * Get info on object asynchronoulsy | |
212 | * |
|
191 | * | |
213 | * @async |
|
192 | * @async | |
214 | * @param objname {string} |
|
193 | * @param objname {string} | |
215 | * @param callback {dict} |
|
194 | * @param callback {dict} | |
216 | * @method object_info_request |
|
195 | * @method object_info_request | |
217 | * |
|
196 | * | |
218 | * @example |
|
197 | * @example | |
219 | * |
|
198 | * | |
220 | * When calling this method pass a callbacks structure of the form: |
|
199 | * When calling this method pass a callbacks structure of the form: | |
221 | * |
|
200 | * | |
222 | * callbacks = { |
|
201 | * callbacks = { | |
223 | * 'object_info_reply': object_info_reply_callback |
|
202 | * 'object_info_reply': object_info_reply_callback | |
224 | * } |
|
203 | * } | |
225 | * |
|
204 | * | |
226 | * The `object_info_reply_callback` will be passed the content object of the |
|
205 | * The `object_info_reply_callback` will be passed the content object of the | |
227 | * |
|
206 | * | |
228 | * `object_into_reply` message documented in |
|
207 | * `object_into_reply` message documented in | |
229 | * [IPython dev documentation](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information) |
|
208 | * [IPython dev documentation](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information) | |
230 | */ |
|
209 | */ | |
231 | Kernel.prototype.object_info_request = function (objname, callbacks) { |
|
210 | Kernel.prototype.object_info_request = function (objname, callbacks) { | |
232 | if(typeof(objname)!=null && objname!=null) |
|
211 | if(typeof(objname)!=null && objname!=null) | |
233 | { |
|
212 | { | |
234 | var content = { |
|
213 | var content = { | |
235 | oname : objname.toString(), |
|
214 | oname : objname.toString(), | |
236 | }; |
|
215 | }; | |
237 | var msg = this._get_msg("object_info_request", content); |
|
216 | var msg = this._get_msg("object_info_request", content); | |
238 | this.shell_channel.send(JSON.stringify(msg)); |
|
217 | this.shell_channel.send(JSON.stringify(msg)); | |
239 | this.set_callbacks_for_msg(msg.header.msg_id, callbacks); |
|
218 | this.set_callbacks_for_msg(msg.header.msg_id, callbacks); | |
240 | return msg.header.msg_id; |
|
219 | return msg.header.msg_id; | |
241 | } |
|
220 | } | |
242 | return; |
|
221 | return; | |
243 | } |
|
222 | } | |
244 |
|
223 | |||
245 | /** |
|
224 | /** | |
246 | * Execute given code into kernel, and pass result to callback. |
|
225 | * Execute given code into kernel, and pass result to callback. | |
247 | * |
|
226 | * | |
248 | * @async |
|
227 | * @async | |
249 | * @method execute |
|
228 | * @method execute | |
250 | * @param {string} code |
|
229 | * @param {string} code | |
251 | * @param callback {Object} With the following keys |
|
230 | * @param callback {Object} With the following keys | |
252 | * @param callback.'execute_reply' {function} |
|
231 | * @param callback.'execute_reply' {function} | |
253 | * @param callback.'output' {function} |
|
232 | * @param callback.'output' {function} | |
254 | * @param callback.'clear_output' {function} |
|
233 | * @param callback.'clear_output' {function} | |
255 | * @param callback.'set_next_input' {function} |
|
234 | * @param callback.'set_next_input' {function} | |
256 | * @param {object} [options] |
|
235 | * @param {object} [options] | |
257 | * @param [options.silent=false] {Boolean} |
|
236 | * @param [options.silent=false] {Boolean} | |
258 | * @param [options.user_expressions=empty_dict] {Dict} |
|
237 | * @param [options.user_expressions=empty_dict] {Dict} | |
259 | * @param [options.user_variables=empty_list] {List od Strings} |
|
238 | * @param [options.user_variables=empty_list] {List od Strings} | |
260 | * @param [options.allow_stdin=false] {Boolean} true|false |
|
239 | * @param [options.allow_stdin=false] {Boolean} true|false | |
261 | * |
|
240 | * | |
262 | * @example |
|
241 | * @example | |
263 | * |
|
242 | * | |
264 | * The options object should contain the options for the execute call. Its default |
|
243 | * The options object should contain the options for the execute call. Its default | |
265 | * values are: |
|
244 | * values are: | |
266 | * |
|
245 | * | |
267 | * options = { |
|
246 | * options = { | |
268 | * silent : true, |
|
247 | * silent : true, | |
269 | * user_variables : [], |
|
248 | * user_variables : [], | |
270 | * user_expressions : {}, |
|
249 | * user_expressions : {}, | |
271 | * allow_stdin : false |
|
250 | * allow_stdin : false | |
272 | * } |
|
251 | * } | |
273 | * |
|
252 | * | |
274 | * When calling this method pass a callbacks structure of the form: |
|
253 | * When calling this method pass a callbacks structure of the form: | |
275 | * |
|
254 | * | |
276 | * callbacks = { |
|
255 | * callbacks = { | |
277 | * 'execute_reply': execute_reply_callback, |
|
256 | * 'execute_reply': execute_reply_callback, | |
278 | * 'output': output_callback, |
|
257 | * 'output': output_callback, | |
279 | * 'clear_output': clear_output_callback, |
|
258 | * 'clear_output': clear_output_callback, | |
280 | * 'set_next_input': set_next_input_callback |
|
259 | * 'set_next_input': set_next_input_callback | |
281 | * } |
|
260 | * } | |
282 | * |
|
261 | * | |
283 | * The `execute_reply_callback` will be passed the content and metadata |
|
262 | * The `execute_reply_callback` will be passed the content and metadata | |
284 | * objects of the `execute_reply` message documented |
|
263 | * objects of the `execute_reply` message documented | |
285 | * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#execute) |
|
264 | * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#execute) | |
286 | * |
|
265 | * | |
287 | * The `output_callback` will be passed `msg_type` ('stream','display_data','pyout','pyerr') |
|
266 | * The `output_callback` will be passed `msg_type` ('stream','display_data','pyout','pyerr') | |
288 | * of the output and the content and metadata objects of the PUB/SUB channel that contains the |
|
267 | * of the output and the content and metadata objects of the PUB/SUB channel that contains the | |
289 | * output: |
|
268 | * output: | |
290 | * |
|
269 | * | |
291 | * http://ipython.org/ipython-doc/dev/development/messaging.html#messages-on-the-pub-sub-socket |
|
270 | * http://ipython.org/ipython-doc/dev/development/messaging.html#messages-on-the-pub-sub-socket | |
292 | * |
|
271 | * | |
293 | * The `clear_output_callback` will be passed a content object that contains |
|
272 | * The `clear_output_callback` will be passed a content object that contains | |
294 | * stdout, stderr and other fields that are booleans, as well as the metadata object. |
|
273 | * stdout, stderr and other fields that are booleans, as well as the metadata object. | |
295 | * |
|
274 | * | |
296 | * The `set_next_input_callback` will be passed the text that should become the next |
|
275 | * The `set_next_input_callback` will be passed the text that should become the next | |
297 | * input cell. |
|
276 | * input cell. | |
298 | */ |
|
277 | */ | |
299 | Kernel.prototype.execute = function (code, callbacks, options) { |
|
278 | Kernel.prototype.execute = function (code, callbacks, options) { | |
300 |
|
279 | |||
301 | var content = { |
|
280 | var content = { | |
302 | code : code, |
|
281 | code : code, | |
303 | silent : true, |
|
282 | silent : true, | |
304 | user_variables : [], |
|
283 | user_variables : [], | |
305 | user_expressions : {}, |
|
284 | user_expressions : {}, | |
306 | allow_stdin : false |
|
285 | allow_stdin : false | |
307 | }; |
|
286 | }; | |
308 | $.extend(true, content, options) |
|
287 | $.extend(true, content, options) | |
309 | $([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content}); |
|
288 | $([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content}); | |
310 | var msg = this._get_msg("execute_request", content); |
|
289 | var msg = this._get_msg("execute_request", content); | |
311 | this.shell_channel.send(JSON.stringify(msg)); |
|
290 | this.shell_channel.send(JSON.stringify(msg)); | |
312 | this.set_callbacks_for_msg(msg.header.msg_id, callbacks); |
|
291 | this.set_callbacks_for_msg(msg.header.msg_id, callbacks); | |
313 | return msg.header.msg_id; |
|
292 | return msg.header.msg_id; | |
314 | }; |
|
293 | }; | |
315 |
|
294 | |||
316 | /** |
|
295 | /** | |
317 | * When calling this method pass a callbacks structure of the form: |
|
296 | * When calling this method pass a callbacks structure of the form: | |
318 | * |
|
297 | * | |
319 | * callbacks = { |
|
298 | * callbacks = { | |
320 | * 'complete_reply': complete_reply_callback |
|
299 | * 'complete_reply': complete_reply_callback | |
321 | * } |
|
300 | * } | |
322 | * |
|
301 | * | |
323 | * The `complete_reply_callback` will be passed the content object of the |
|
302 | * The `complete_reply_callback` will be passed the content object of the | |
324 | * `complete_reply` message documented |
|
303 | * `complete_reply` message documented | |
325 | * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete) |
|
304 | * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete) | |
326 | * |
|
305 | * | |
327 | * @method complete |
|
306 | * @method complete | |
328 | * @param line {integer} |
|
307 | * @param line {integer} | |
329 | * @param cursor_pos {integer} |
|
308 | * @param cursor_pos {integer} | |
330 | * @param {dict} callbacks |
|
309 | * @param {dict} callbacks | |
331 | * @param callbacks.complete_reply {function} `complete_reply_callback` |
|
310 | * @param callbacks.complete_reply {function} `complete_reply_callback` | |
332 | * |
|
311 | * | |
333 | */ |
|
312 | */ | |
334 | Kernel.prototype.complete = function (line, cursor_pos, callbacks) { |
|
313 | Kernel.prototype.complete = function (line, cursor_pos, callbacks) { | |
335 | callbacks = callbacks || {}; |
|
314 | callbacks = callbacks || {}; | |
336 | var content = { |
|
315 | var content = { | |
337 | text : '', |
|
316 | text : '', | |
338 | line : line, |
|
317 | line : line, | |
339 | cursor_pos : cursor_pos |
|
318 | cursor_pos : cursor_pos | |
340 | }; |
|
319 | }; | |
341 | var msg = this._get_msg("complete_request", content); |
|
320 | var msg = this._get_msg("complete_request", content); | |
342 | this.shell_channel.send(JSON.stringify(msg)); |
|
321 | this.shell_channel.send(JSON.stringify(msg)); | |
343 | this.set_callbacks_for_msg(msg.header.msg_id, callbacks); |
|
322 | this.set_callbacks_for_msg(msg.header.msg_id, callbacks); | |
344 | return msg.header.msg_id; |
|
323 | return msg.header.msg_id; | |
345 | }; |
|
324 | }; | |
346 |
|
325 | |||
347 |
|
326 | |||
348 | Kernel.prototype.interrupt = function () { |
|
327 | Kernel.prototype.interrupt = function () { | |
349 | if (this.running) { |
|
328 | if (this.running) { | |
350 | $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this}); |
|
329 | $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this}); | |
351 | $.post(this.kernel_url + "/interrupt"); |
|
330 | $.post(this.kernel_url + "/interrupt"); | |
352 | }; |
|
331 | }; | |
353 | }; |
|
332 | }; | |
354 |
|
333 | |||
355 |
|
334 | |||
356 | Kernel.prototype.kill = function () { |
|
335 | Kernel.prototype.kill = function () { | |
357 | if (this.running) { |
|
336 | if (this.running) { | |
358 | this.running = false; |
|
337 | this.running = false; | |
359 | var settings = { |
|
338 | var settings = { | |
360 | cache : false, |
|
339 | cache : false, | |
361 | type : "DELETE" |
|
340 | type : "DELETE" | |
362 | }; |
|
341 | }; | |
363 | $.ajax(this.kernel_url, settings); |
|
342 | $.ajax(this.kernel_url, settings); | |
364 | }; |
|
343 | }; | |
365 | }; |
|
344 | }; | |
366 |
|
345 | |||
367 |
|
346 | |||
368 | // Reply handlers. |
|
347 | // Reply handlers. | |
369 |
|
348 | |||
370 | Kernel.prototype.get_callbacks_for_msg = function (msg_id) { |
|
349 | Kernel.prototype.get_callbacks_for_msg = function (msg_id) { | |
371 | var callbacks = this._msg_callbacks[msg_id]; |
|
350 | var callbacks = this._msg_callbacks[msg_id]; | |
372 | return callbacks; |
|
351 | return callbacks; | |
373 | }; |
|
352 | }; | |
374 |
|
353 | |||
375 |
|
354 | |||
376 | Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) { |
|
355 | Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) { | |
377 | this._msg_callbacks[msg_id] = callbacks || {}; |
|
356 | this._msg_callbacks[msg_id] = callbacks || {}; | |
378 | } |
|
357 | } | |
379 |
|
358 | |||
380 |
|
359 | |||
381 | Kernel.prototype._handle_shell_reply = function (e) { |
|
360 | Kernel.prototype._handle_shell_reply = function (e) { | |
382 | var reply = $.parseJSON(e.data); |
|
361 | var reply = $.parseJSON(e.data); | |
383 | $([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply}); |
|
362 | $([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply}); | |
384 | var header = reply.header; |
|
363 | var header = reply.header; | |
385 | var content = reply.content; |
|
364 | var content = reply.content; | |
386 | var metadata = reply.metadata; |
|
365 | var metadata = reply.metadata; | |
387 | var msg_type = header.msg_type; |
|
366 | var msg_type = header.msg_type; | |
388 | var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id); |
|
367 | var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id); | |
389 | if (callbacks !== undefined) { |
|
368 | if (callbacks !== undefined) { | |
390 | var cb = callbacks[msg_type]; |
|
369 | var cb = callbacks[msg_type]; | |
391 | if (cb !== undefined) { |
|
370 | if (cb !== undefined) { | |
392 | cb(content, metadata); |
|
371 | cb(content, metadata); | |
393 | } |
|
372 | } | |
394 | }; |
|
373 | }; | |
395 |
|
374 | |||
396 | if (content.payload !== undefined) { |
|
375 | if (content.payload !== undefined) { | |
397 | var payload = content.payload || []; |
|
376 | var payload = content.payload || []; | |
398 | this._handle_payload(callbacks, payload); |
|
377 | this._handle_payload(callbacks, payload); | |
399 | } |
|
378 | } | |
400 | }; |
|
379 | }; | |
401 |
|
380 | |||
402 |
|
381 | |||
403 | Kernel.prototype._handle_payload = function (callbacks, payload) { |
|
382 | Kernel.prototype._handle_payload = function (callbacks, payload) { | |
404 | var l = payload.length; |
|
383 | var l = payload.length; | |
405 | // Payloads are handled by triggering events because we don't want the Kernel |
|
384 | // Payloads are handled by triggering events because we don't want the Kernel | |
406 | // to depend on the Notebook or Pager classes. |
|
385 | // to depend on the Notebook or Pager classes. | |
407 | for (var i=0; i<l; i++) { |
|
386 | for (var i=0; i<l; i++) { | |
408 | if (payload[i].source === 'IPython.zmq.page.page') { |
|
387 | if (payload[i].source === 'IPython.zmq.page.page') { | |
409 | var data = {'text':payload[i].text} |
|
388 | var data = {'text':payload[i].text} | |
410 | $([IPython.events]).trigger('open_with_text.Pager', data); |
|
389 | $([IPython.events]).trigger('open_with_text.Pager', data); | |
411 | } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') { |
|
390 | } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') { | |
412 | if (callbacks.set_next_input !== undefined) { |
|
391 | if (callbacks.set_next_input !== undefined) { | |
413 | callbacks.set_next_input(payload[i].text) |
|
392 | callbacks.set_next_input(payload[i].text) | |
414 | } |
|
393 | } | |
415 | } |
|
394 | } | |
416 | }; |
|
395 | }; | |
417 | }; |
|
396 | }; | |
418 |
|
397 | |||
419 |
|
398 | |||
420 | Kernel.prototype._handle_iopub_reply = function (e) { |
|
399 | Kernel.prototype._handle_iopub_reply = function (e) { | |
421 | var reply = $.parseJSON(e.data); |
|
400 | var reply = $.parseJSON(e.data); | |
422 | var content = reply.content; |
|
401 | var content = reply.content; | |
423 | var msg_type = reply.header.msg_type; |
|
402 | var msg_type = reply.header.msg_type; | |
424 | var metadata = reply.metadata; |
|
403 | var metadata = reply.metadata; | |
425 | var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id); |
|
404 | var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id); | |
426 | if (msg_type !== 'status' && callbacks === undefined) { |
|
405 | if (msg_type !== 'status' && callbacks === undefined) { | |
427 | // Message not from one of this notebook's cells and there are no |
|
406 | // Message not from one of this notebook's cells and there are no | |
428 | // callbacks to handle it. |
|
407 | // callbacks to handle it. | |
429 | return; |
|
408 | return; | |
430 | } |
|
409 | } | |
431 | var output_types = ['stream','display_data','pyout','pyerr']; |
|
410 | var output_types = ['stream','display_data','pyout','pyerr']; | |
432 | if (output_types.indexOf(msg_type) >= 0) { |
|
411 | if (output_types.indexOf(msg_type) >= 0) { | |
433 | var cb = callbacks['output']; |
|
412 | var cb = callbacks['output']; | |
434 | if (cb !== undefined) { |
|
413 | if (cb !== undefined) { | |
435 | cb(msg_type, content, metadata); |
|
414 | cb(msg_type, content, metadata); | |
436 | } |
|
415 | } | |
437 | } else if (msg_type === 'status') { |
|
416 | } else if (msg_type === 'status') { | |
438 | if (content.execution_state === 'busy') { |
|
417 | if (content.execution_state === 'busy') { | |
439 | $([IPython.events]).trigger('status_busy.Kernel', {kernel: this}); |
|
418 | $([IPython.events]).trigger('status_busy.Kernel', {kernel: this}); | |
440 | } else if (content.execution_state === 'idle') { |
|
419 | } else if (content.execution_state === 'idle') { | |
441 | $([IPython.events]).trigger('status_idle.Kernel', {kernel: this}); |
|
420 | $([IPython.events]).trigger('status_idle.Kernel', {kernel: this}); | |
442 | } else if (content.execution_state === 'dead') { |
|
421 | } else if (content.execution_state === 'dead') { | |
443 | this.stop_channels(); |
|
422 | this.stop_channels(); | |
444 | $([IPython.events]).trigger('status_dead.Kernel', {kernel: this}); |
|
423 | $([IPython.events]).trigger('status_dead.Kernel', {kernel: this}); | |
445 | }; |
|
424 | }; | |
446 | } else if (msg_type === 'clear_output') { |
|
425 | } else if (msg_type === 'clear_output') { | |
447 | var cb = callbacks['clear_output']; |
|
426 | var cb = callbacks['clear_output']; | |
448 | if (cb !== undefined) { |
|
427 | if (cb !== undefined) { | |
449 | cb(content, metadata); |
|
428 | cb(content, metadata); | |
450 | } |
|
429 | } | |
451 | }; |
|
430 | }; | |
452 | }; |
|
431 | }; | |
453 |
|
432 | |||
454 |
|
433 | |||
455 | IPython.Kernel = Kernel; |
|
434 | IPython.Kernel = Kernel; | |
456 |
|
435 | |||
457 | return IPython; |
|
436 | return IPython; | |
458 |
|
437 | |||
459 | }(IPython)); |
|
438 | }(IPython)); | |
460 |
|
439 |
@@ -1,141 +1,188 | |||||
1 | //---------------------------------------------------------------------------- |
|
1 | //---------------------------------------------------------------------------- | |
2 | // Copyright (C) 2012 The IPython Development Team |
|
2 | // Copyright (C) 2012 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 | // Notification widget |
|
9 | // Notification widget | |
10 | //============================================================================ |
|
10 | //============================================================================ | |
11 |
|
11 | |||
12 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
13 | "use strict"; |
|
13 | "use strict"; | |
14 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
15 |
|
15 | |||
16 |
|
16 | |||
17 | var NotificationArea = function (selector) { |
|
17 | var NotificationArea = function (selector) { | |
18 | this.selector = selector; |
|
18 | this.selector = selector; | |
19 | if (this.selector !== undefined) { |
|
19 | if (this.selector !== undefined) { | |
20 | this.element = $(selector); |
|
20 | this.element = $(selector); | |
21 | } |
|
21 | } | |
22 | this.widget_dict = {}; |
|
22 | this.widget_dict = {}; | |
23 | }; |
|
23 | }; | |
24 |
|
24 | |||
25 | NotificationArea.prototype.temp_message = function (msg, timeout, css_class) { |
|
25 | NotificationArea.prototype.temp_message = function (msg, timeout, css_class) { | |
26 | var uuid = utils.uuid(); |
|
26 | var uuid = utils.uuid(); | |
27 | if( css_class == 'danger') {css_class = 'ui-state-error';} |
|
27 | if( css_class == 'danger') {css_class = 'ui-state-error';} | |
28 | if( css_class == 'warning') {css_class = 'ui-state-highlight';} |
|
28 | if( css_class == 'warning') {css_class = 'ui-state-highlight';} | |
29 | var tdiv = $('<div>') |
|
29 | var tdiv = $('<div>') | |
30 | .attr('id',uuid) |
|
30 | .attr('id',uuid) | |
31 | .addClass('notification_widget ui-widget ui-widget-content ui-corner-all') |
|
31 | .addClass('notification_widget ui-widget ui-widget-content ui-corner-all') | |
32 | .addClass('border-box-sizing') |
|
32 | .addClass('border-box-sizing') | |
33 | .addClass(css_class) |
|
33 | .addClass(css_class) | |
34 | .hide() |
|
34 | .hide() | |
35 | .text(msg); |
|
35 | .text(msg); | |
36 |
|
36 | |||
37 | $(this.selector).append(tdiv); |
|
37 | $(this.selector).append(tdiv); | |
38 | var tmout = Math.max(1500,(timeout||1500)); |
|
38 | var tmout = Math.max(1500,(timeout||1500)); | |
39 | tdiv.fadeIn(100); |
|
39 | tdiv.fadeIn(100); | |
40 |
|
40 | |||
41 | setTimeout(function () { |
|
41 | setTimeout(function () { | |
42 | tdiv.fadeOut(100, function () {tdiv.remove();}); |
|
42 | tdiv.fadeOut(100, function () {tdiv.remove();}); | |
43 | }, tmout); |
|
43 | }, tmout); | |
44 | }; |
|
44 | }; | |
45 |
|
45 | |||
46 | NotificationArea.prototype.widget = function(name) { |
|
46 | NotificationArea.prototype.widget = function(name) { | |
47 | if(this.widget_dict[name] == undefined) { |
|
47 | if(this.widget_dict[name] == undefined) { | |
48 | return this.new_notification_widget(name); |
|
48 | return this.new_notification_widget(name); | |
49 | } |
|
49 | } | |
50 | return this.get_widget(name); |
|
50 | return this.get_widget(name); | |
51 | }; |
|
51 | }; | |
52 |
|
52 | |||
53 | NotificationArea.prototype.get_widget = function(name) { |
|
53 | NotificationArea.prototype.get_widget = function(name) { | |
54 | if(this.widget_dict[name] == undefined) { |
|
54 | if(this.widget_dict[name] == undefined) { | |
55 | throw('no widgets with this name'); |
|
55 | throw('no widgets with this name'); | |
56 | } |
|
56 | } | |
57 | return this.widget_dict[name]; |
|
57 | return this.widget_dict[name]; | |
58 | }; |
|
58 | }; | |
59 |
|
59 | |||
60 | NotificationArea.prototype.new_notification_widget = function(name) { |
|
60 | NotificationArea.prototype.new_notification_widget = function(name) { | |
61 | if(this.widget_dict[name] != undefined) { |
|
61 | if(this.widget_dict[name] != undefined) { | |
62 | throw('widget with that name already exists ! '); |
|
62 | throw('widget with that name already exists ! '); | |
63 | } |
|
63 | } | |
64 | var div = $('<div/>').attr('id','notification_'+name); |
|
64 | var div = $('<div/>').attr('id','notification_'+name); | |
65 | $(this.selector).append(div); |
|
65 | $(this.selector).append(div); | |
66 | this.widget_dict[name] = new IPython.NotificationWidget('#notification_'+name); |
|
66 | this.widget_dict[name] = new IPython.NotificationWidget('#notification_'+name); | |
67 | return this.widget_dict[name]; |
|
67 | return this.widget_dict[name]; | |
68 | }; |
|
68 | }; | |
69 |
|
69 | |||
70 | NotificationArea.prototype.init_notification_widgets = function() { |
|
70 | NotificationArea.prototype.init_notification_widgets = function() { | |
71 | var knw = this.new_notification_widget('kernel'); |
|
71 | var knw = this.new_notification_widget('kernel'); | |
72 |
|
72 | |||
73 | // Kernel events |
|
73 | // Kernel events | |
74 | $([IPython.events]).on('status_idle.Kernel',function () { |
|
74 | $([IPython.events]).on('status_idle.Kernel',function () { | |
75 | IPython.save_widget.update_document_title(); |
|
75 | IPython.save_widget.update_document_title(); | |
76 | knw.set_message('Kernel Idle',200); |
|
76 | knw.set_message('Kernel Idle',200); | |
77 | } |
|
77 | } | |
78 | ); |
|
78 | ); | |
79 |
|
79 | |||
80 | $([IPython.events]).on('status_busy.Kernel',function () { |
|
80 | $([IPython.events]).on('status_busy.Kernel',function () { | |
81 | window.document.title='(Busy) '+window.document.title; |
|
81 | window.document.title='(Busy) '+window.document.title; | |
82 | knw.set_message("Kernel busy"); |
|
82 | knw.set_message("Kernel busy"); | |
83 | }); |
|
83 | }); | |
84 |
|
84 | |||
85 | $([IPython.events]).on('status_restarting.Kernel',function () { |
|
85 | $([IPython.events]).on('status_restarting.Kernel',function () { | |
86 | IPython.save_widget.update_document_title(); |
|
86 | IPython.save_widget.update_document_title(); | |
87 | knw.set_message("Restarting kernel",1000); |
|
87 | knw.set_message("Restarting kernel",1000); | |
88 | }); |
|
88 | }); | |
89 |
|
89 | |||
90 | $([IPython.events]).on('status_interrupting.Kernel',function () { |
|
90 | $([IPython.events]).on('status_interrupting.Kernel',function () { | |
91 | knw.set_message("Interrupting kernel"); |
|
91 | knw.set_message("Interrupting kernel"); | |
92 | }); |
|
92 | }); | |
93 |
|
93 | |||
94 | $([IPython.events]).on('status_dead.Kernel',function () { |
|
94 | $([IPython.events]).on('status_dead.Kernel',function () { | |
95 | var dialog = $('<div/>'); |
|
95 | var dialog = $('<div/>'); | |
96 | dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.'); |
|
96 | dialog.html('The kernel has died, would you like to restart it?' + | |
|
97 | ' If you do not restart the kernel, you will be able to save' + | |||
|
98 | ' the notebook, but running code will not work until the notebook' + | |||
|
99 | ' is reopened.' | |||
|
100 | ); | |||
97 | $(document).append(dialog); |
|
101 | $(document).append(dialog); | |
98 | dialog.dialog({ |
|
102 | dialog.dialog({ | |
99 | resizable: false, |
|
103 | resizable: false, | |
100 | modal: true, |
|
104 | modal: true, | |
101 | title: "Dead kernel", |
|
105 | title: "Dead kernel", | |
|
106 | close: function(event, ui) {$(this).dialog('destroy').remove();}, | |||
102 | buttons : { |
|
107 | buttons : { | |
103 | "Restart": function () { |
|
108 | "Restart": function () { | |
104 | $([IPython.events]).trigger('status_restarting.Kernel'); |
|
109 | $([IPython.events]).trigger('status_restarting.Kernel'); | |
105 | IPython.notebook.start_kernel(); |
|
110 | IPython.notebook.start_kernel(); | |
106 | $(this).dialog('close'); |
|
111 | $(this).dialog('close'); | |
107 | }, |
|
112 | }, | |
108 |
" |
|
113 | "Don't restart": function () { | |
109 | $(this).dialog('close'); |
|
114 | $(this).dialog('close'); | |
110 | } |
|
115 | } | |
111 | } |
|
116 | } | |
112 | }); |
|
117 | }); | |
113 | }); |
|
118 | }); | |
114 |
|
119 | |||
|
120 | $([IPython.events]).on('websocket_closed.Kernel', function (event, data) { | |||
|
121 | var kernel = data.kernel; | |||
|
122 | var ws_url = data.ws_url; | |||
|
123 | var early = data.early; | |||
|
124 | var msg; | |||
|
125 | console.log(early); | |||
|
126 | if (!early) { | |||
|
127 | knw.set_message('Reconnecting WebSockets', 1000); | |||
|
128 | setTimeout(function () { | |||
|
129 | kernel.start_channels(); | |||
|
130 | }, 5000); | |||
|
131 | return; | |||
|
132 | } | |||
|
133 | console.log('WebSocket connection failed: ', ws_url) | |||
|
134 | msg = "A WebSocket connection to could not be established." + | |||
|
135 | " You will NOT be able to run code. Check your" + | |||
|
136 | " network connection or notebook server configuration."; | |||
|
137 | var dialog = $('<div/>'); | |||
|
138 | dialog.html(msg); | |||
|
139 | $(document).append(dialog); | |||
|
140 | dialog.dialog({ | |||
|
141 | resizable: false, | |||
|
142 | modal: true, | |||
|
143 | title: "WebSocket connection failed", | |||
|
144 | closeText: "", | |||
|
145 | close: function(event, ui) {$(this).dialog('destroy').remove();}, | |||
|
146 | buttons : { | |||
|
147 | "OK": function () { | |||
|
148 | $(this).dialog('close'); | |||
|
149 | }, | |||
|
150 | "Reconnect": function () { | |||
|
151 | knw.set_message('Reconnecting WebSockets', 1000); | |||
|
152 | setTimeout(function () { | |||
|
153 | kernel.start_channels(); | |||
|
154 | }, 5000); | |||
|
155 | $(this).dialog('close'); | |||
|
156 | } | |||
|
157 | } | |||
|
158 | }); | |||
|
159 | }); | |||
|
160 | ||||
|
161 | ||||
115 | var nnw = this.new_notification_widget('notebook'); |
|
162 | var nnw = this.new_notification_widget('notebook'); | |
116 |
|
163 | |||
117 | // Notebook events |
|
164 | // Notebook events | |
118 | $([IPython.events]).on('notebook_loading.Notebook', function () { |
|
165 | $([IPython.events]).on('notebook_loading.Notebook', function () { | |
119 | nnw.set_message("Loading notebook",500); |
|
166 | nnw.set_message("Loading notebook",500); | |
120 | }); |
|
167 | }); | |
121 | $([IPython.events]).on('notebook_loaded.Notebook', function () { |
|
168 | $([IPython.events]).on('notebook_loaded.Notebook', function () { | |
122 | nnw.set_message("Notebook loaded",500); |
|
169 | nnw.set_message("Notebook loaded",500); | |
123 | }); |
|
170 | }); | |
124 | $([IPython.events]).on('notebook_saving.Notebook', function () { |
|
171 | $([IPython.events]).on('notebook_saving.Notebook', function () { | |
125 | nnw.set_message("Saving notebook",500); |
|
172 | nnw.set_message("Saving notebook",500); | |
126 | }); |
|
173 | }); | |
127 | $([IPython.events]).on('notebook_saved.Notebook', function () { |
|
174 | $([IPython.events]).on('notebook_saved.Notebook', function () { | |
128 | nnw.set_message("Notebook saved",2000); |
|
175 | nnw.set_message("Notebook saved",2000); | |
129 | }); |
|
176 | }); | |
130 | $([IPython.events]).on('notebook_save_failed.Notebook', function () { |
|
177 | $([IPython.events]).on('notebook_save_failed.Notebook', function () { | |
131 | nnw.set_message("Notebook save failed"); |
|
178 | nnw.set_message("Notebook save failed"); | |
132 | }); |
|
179 | }); | |
133 |
|
180 | |||
134 | }; |
|
181 | }; | |
135 |
|
182 | |||
136 | IPython.NotificationArea = NotificationArea; |
|
183 | IPython.NotificationArea = NotificationArea; | |
137 |
|
184 | |||
138 | return IPython; |
|
185 | return IPython; | |
139 |
|
186 | |||
140 | }(IPython)); |
|
187 | }(IPython)); | |
141 |
|
188 |
General Comments 0
You need to be logged in to leave comments.
Login now