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