##// END OF EJS Templates
fix kernel change breaking new notebook list
Mathieu -
Show More
@@ -1,204 +1,223 b''
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'jquery',
6 'jquery',
7 'base/js/utils',
7 'base/js/utils',
8 ], function(IPython, $, utils) {
8 ], function(IPython, $, utils) {
9 "use strict";
9 "use strict";
10
10
11 var KernelSelector = function(selector, notebook) {
11 var KernelSelector = function(selector, notebook) {
12 var that = this;
12 var that = this;
13 this.selector = selector;
13 this.selector = selector;
14 this.notebook = notebook;
14 this.notebook = notebook;
15 this.notebook.set_kernelselector(this);
15 this.notebook.set_kernelselector(this);
16 this.events = notebook.events;
16 this.events = notebook.events;
17 this.current_selection = null;
17 this.current_selection = null;
18 this.kernelspecs = {};
18 this.kernelspecs = {};
19 if (this.selector !== undefined) {
19 if (this.selector !== undefined) {
20 this.element = $(selector);
20 this.element = $(selector);
21 this.request_kernelspecs();
21 this.request_kernelspecs();
22 }
22 }
23 this.bind_events();
23 this.bind_events();
24 // Make the object globally available for user convenience & inspection
24 // Make the object globally available for user convenience & inspection
25 IPython.kernelselector = this;
25 IPython.kernelselector = this;
26 this._finish_load = null;
26 this._finish_load = null;
27 this.loaded = new Promise(function(resolve, reject) {
27 this.loaded = new Promise(function(resolve, reject) {
28 that._finish_load = resolve;
28 that._finish_load = resolve;
29 });
29 });
30
30
31 Object.seal(this);
31 Object.seal(this);
32 };
32 };
33
33
34 KernelSelector.prototype.request_kernelspecs = function() {
34 KernelSelector.prototype.request_kernelspecs = function() {
35 var url = utils.url_join_encode(this.notebook.base_url, 'api/kernelspecs');
35 var url = utils.url_join_encode(this.notebook.base_url, 'api/kernelspecs');
36 utils.promising_ajax(url).then($.proxy(this._got_kernelspecs, this));
36 utils.promising_ajax(url).then($.proxy(this._got_kernelspecs, this));
37 };
37 };
38
38
39 KernelSelector.prototype._got_kernelspecs = function(data) {
39 KernelSelector.prototype._got_kernelspecs = function(data) {
40 this.kernelspecs = data.kernelspecs;
40 this.kernelspecs = data.kernelspecs;
41 var change_kernel_submenu = $("#menu-change-kernel-submenu");
41 var change_kernel_submenu = $("#menu-change-kernel-submenu");
42 var new_notebook_submenu = $("#menu-new-notebook-submenu");
42 var new_notebook_submenu = $("#menu-new-notebook-submenu");
43
43
44 var keys = Object.keys(data.kernelspecs).sort(function (a, b) {
44 var keys = Object.keys(data.kernelspecs).sort(function (a, b) {
45 // sort by display_name
45 // sort by display_name
46 var da = data.kernelspecs[a].spec.display_name;
46 var da = data.kernelspecs[a].spec.display_name;
47 var db = data.kernelspecs[b].spec.display_name;
47 var db = data.kernelspecs[b].spec.display_name;
48 if (da === db) {
48 if (da === db) {
49 return 0;
49 return 0;
50 } else if (da > db) {
50 } else if (da > db) {
51 return 1;
51 return 1;
52 } else {
52 } else {
53 return -1;
53 return -1;
54 }
54 }
55 });
55 });
56
56
57 var i, ks, ks_submenu_entry;
57 var i, ks, ks_submenu_entry;
58 // Create the Kernel > Change kernel submenu
58 // Create the Kernel > Change kernel submenu
59 for (i = 0; i < keys.length; i++) {
59 for (i = 0; i < keys.length; i++) {
60 ks = this.kernelspecs[keys[i]];
60 ks = this.kernelspecs[keys[i]];
61 ks_submenu_entry = $("<li>").attr("id", "kernel-submenu-"+ks.name).append($('<a>')
61 ks_submenu_entry = $("<li>").attr("id", "kernel-submenu-"+ks.name).append($('<a>')
62 .attr('href', '#')
62 .attr('href', '#')
63 .click($.proxy(this.set_kernel, this, ks.name))
63 .click($.proxy(this.set_kernel, this, ks.name))
64 .text(ks.spec.display_name));
64 .text(ks.spec.display_name));
65 change_kernel_submenu.append(ks_submenu_entry);
65 change_kernel_submenu.append(ks_submenu_entry);
66 }
66 }
67
67
68 // Create the File > New Notebook submenu
68 // Create the File > New Notebook submenu
69 for (i = 0; i < keys.length; i++) {
69 for (i = 0; i < keys.length; i++) {
70 ks = this.kernelspecs[keys[i]];
70 ks = this.kernelspecs[keys[i]];
71 ks_submenu_entry = $("<li>").attr("id", "new-notebook-submenu-"+ks.name).append($('<a>')
71 ks_submenu_entry = $("<li>").attr("id", "new-notebook-submenu-"+ks.name).append($('<a>')
72 .attr('href', '#')
72 .attr('href', '#')
73 .click($.proxy(this.new_notebook, this, ks.name))
73 .click($.proxy(this.new_notebook, this, ks.name))
74 .text(ks.spec.display_name));
74 .text(ks.spec.display_name));
75 new_notebook_submenu.append(ks_submenu_entry);
75 new_notebook_submenu.append(ks_submenu_entry);
76 }
76 }
77 // trigger loaded promise
77 // trigger loaded promise
78 this._finish_load();
78 this._finish_load();
79 };
79 };
80
80
81 KernelSelector.prototype._spec_changed = function (event, ks) {
81 KernelSelector.prototype._spec_changed = function (event, ks) {
82 /** event handler for spec_changed */
82 /** event handler for spec_changed */
83
83
84 // update selection
84 // update selection
85 this.current_selection = ks.name;
85 this.current_selection = ks.name;
86
86
87 // put the current kernel at the top of File > New Notebook
87 // put the current kernel at the top of File > New Notebook
88 var cur_kernel_entry = $("#new-notebook-submenu-" + ks.name);
88 var cur_kernel_entry = $("#new-notebook-submenu-" + ks.name);
89 if (cur_kernel_entry.length) {
89 var parent = cur_kernel_entry.parent();
90 cur_kernel_entry.parent().prepend($("<li>").attr("class","divider"))
90 // do something only if there is more than one kernel
91 .prepend(cur_kernel_entry);
91 if (parent.children().length > 1) {
92 // first, sort back the submenu
93 parent.append(
94 parent.children("li[class!='divider']").sort(
95 function (a,b) {
96 var da = $("a",a).text();
97 var db = $("a",b).text();
98 if (da === db) {
99 return 0;
100 } else if (da > db) {
101 return 1;
102 } else {
103 return -1;
104 }}));
105 // then, if there is no divider yet, add one
106 if (!parent.children("li[class='divider']").length) {
107 parent.prepend($("<li>").attr("class","divider"));
108 }
109 // finally, put the current kernel at the top
110 parent.prepend(cur_kernel_entry);
92 }
111 }
93
112
94 // load logo
113 // load logo
95 var logo_img = this.element.find("img.current_kernel_logo");
114 var logo_img = this.element.find("img.current_kernel_logo");
96 $("#kernel_indicator").find('.kernel_indicator_name').text(ks.spec.display_name);
115 $("#kernel_indicator").find('.kernel_indicator_name').text(ks.spec.display_name);
97 if (ks.resources['logo-64x64']) {
116 if (ks.resources['logo-64x64']) {
98 logo_img.attr("src", ks.resources['logo-64x64']);
117 logo_img.attr("src", ks.resources['logo-64x64']);
99 logo_img.show();
118 logo_img.show();
100 } else {
119 } else {
101 logo_img.hide();
120 logo_img.hide();
102 }
121 }
103
122
104 // load kernel css
123 // load kernel css
105 var css_url = ks.resources['kernel.css'];
124 var css_url = ks.resources['kernel.css'];
106 if (css_url) {
125 if (css_url) {
107 $('#kernel-css').attr('href', css_url);
126 $('#kernel-css').attr('href', css_url);
108 } else {
127 } else {
109 $('#kernel-css').attr('href', '');
128 $('#kernel-css').attr('href', '');
110 }
129 }
111
130
112 // load kernel js
131 // load kernel js
113 if (ks.resources['kernel.js']) {
132 if (ks.resources['kernel.js']) {
114 require([ks.resources['kernel.js']],
133 require([ks.resources['kernel.js']],
115 function (kernel_mod) {
134 function (kernel_mod) {
116 if (kernel_mod && kernel_mod.onload) {
135 if (kernel_mod && kernel_mod.onload) {
117 kernel_mod.onload();
136 kernel_mod.onload();
118 } else {
137 } else {
119 console.warn("Kernel " + ks.name + " has a kernel.js file that does not contain "+
138 console.warn("Kernel " + ks.name + " has a kernel.js file that does not contain "+
120 "any asynchronous module definition. This is undefined behavior "+
139 "any asynchronous module definition. This is undefined behavior "+
121 "and not recommended.");
140 "and not recommended.");
122 }
141 }
123 }, function (err) {
142 }, function (err) {
124 console.warn("Failed to load kernel.js from ", ks.resources['kernel.js'], err);
143 console.warn("Failed to load kernel.js from ", ks.resources['kernel.js'], err);
125 }
144 }
126 );
145 );
127 }
146 }
128 };
147 };
129
148
130 KernelSelector.prototype.set_kernel = function (kernel_name) {
149 KernelSelector.prototype.set_kernel = function (kernel_name) {
131 /** set the kernel by name, ensuring kernelspecs have been loaded, first */
150 /** set the kernel by name, ensuring kernelspecs have been loaded, first */
132 var that = this;
151 var that = this;
133 return this.loaded.then(function () {
152 return this.loaded.then(function () {
134 that._set_kernel(kernel_name);
153 that._set_kernel(kernel_name);
135 });
154 });
136 };
155 };
137
156
138 KernelSelector.prototype._set_kernel = function (kernel_name) {
157 KernelSelector.prototype._set_kernel = function (kernel_name) {
139 /** Actually set the kernel (kernelspecs have been loaded) */
158 /** Actually set the kernel (kernelspecs have been loaded) */
140 if (kernel_name === this.current_selection) {
159 if (kernel_name === this.current_selection) {
141 // only trigger event if value changed
160 // only trigger event if value changed
142 return;
161 return;
143 }
162 }
144 var ks = this.kernelspecs[kernel_name];
163 var ks = this.kernelspecs[kernel_name];
145 if (this.notebook._session_starting) {
164 if (this.notebook._session_starting) {
146 console.error("Cannot change kernel while waiting for pending session start.");
165 console.error("Cannot change kernel while waiting for pending session start.");
147 return;
166 return;
148 }
167 }
149 this.current_selection = kernel_name;
168 this.current_selection = kernel_name;
150 this.events.trigger('spec_changed.Kernel', ks);
169 this.events.trigger('spec_changed.Kernel', ks);
151 };
170 };
152
171
153 KernelSelector.prototype.new_notebook = function (kernel_name) {
172 KernelSelector.prototype.new_notebook = function (kernel_name) {
154
173
155 var w = window.open();
174 var w = window.open();
156 // Create a new notebook in the same path as the current
175 // Create a new notebook in the same path as the current
157 // notebook's path.
176 // notebook's path.
158 var that = this;
177 var that = this;
159 var parent = utils.url_path_split(that.notebook.notebook_path)[0];
178 var parent = utils.url_path_split(that.notebook.notebook_path)[0];
160 that.notebook.contents.new_untitled(parent, {type: "notebook"}).then(
179 that.notebook.contents.new_untitled(parent, {type: "notebook"}).then(
161 function (data) {
180 function (data) {
162 var url = utils.url_join_encode(
181 var url = utils.url_join_encode(
163 that.notebook.base_url, 'notebooks', data.path
182 that.notebook.base_url, 'notebooks', data.path
164 );
183 );
165 url += "?kernel_name=" + kernel_name;
184 url += "?kernel_name=" + kernel_name;
166 w.location = url;
185 w.location = url;
167 },
186 },
168 function(error) {
187 function(error) {
169 w.close();
188 w.close();
170 dialog.modal({
189 dialog.modal({
171 title : 'Creating Notebook Failed',
190 title : 'Creating Notebook Failed',
172 body : "The error was: " + error.message,
191 body : "The error was: " + error.message,
173 buttons : {'OK' : {'class' : 'btn-primary'}}
192 buttons : {'OK' : {'class' : 'btn-primary'}}
174 });
193 });
175 }
194 }
176 );
195 );
177 };
196 };
178
197
179 KernelSelector.prototype.lock_switch = function() {
198 KernelSelector.prototype.lock_switch = function() {
180 // should set a flag and display warning+reload if user want to
199 // should set a flag and display warning+reload if user want to
181 // re-change kernel. As UI discussion never finish
200 // re-change kernel. As UI discussion never finish
182 // making that a separate PR.
201 // making that a separate PR.
183 console.warn('switching kernel is not guaranteed to work !');
202 console.warn('switching kernel is not guaranteed to work !');
184 };
203 };
185
204
186 KernelSelector.prototype.bind_events = function() {
205 KernelSelector.prototype.bind_events = function() {
187 var that = this;
206 var that = this;
188 this.events.on('spec_changed.Kernel', $.proxy(this._spec_changed, this));
207 this.events.on('spec_changed.Kernel', $.proxy(this._spec_changed, this));
189
208
190 this.events.on('kernel_created.Session', function (event, data) {
209 this.events.on('kernel_created.Session', function (event, data) {
191 that.set_kernel(data.kernel.name);
210 that.set_kernel(data.kernel.name);
192 });
211 });
193
212
194 var logo_img = this.element.find("img.current_kernel_logo");
213 var logo_img = this.element.find("img.current_kernel_logo");
195 logo_img.on("load", function() {
214 logo_img.on("load", function() {
196 logo_img.show();
215 logo_img.show();
197 });
216 });
198 logo_img.on("error", function() {
217 logo_img.on("error", function() {
199 logo_img.hide();
218 logo_img.hide();
200 });
219 });
201 };
220 };
202
221
203 return {'KernelSelector': KernelSelector};
222 return {'KernelSelector': KernelSelector};
204 });
223 });
General Comments 0
You need to be logged in to leave comments. Login now