##// END OF EJS Templates
Dont prompt for name.
Jonathan Frederic -
Show More
@@ -1,630 +1,540 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 'base/js/dialog',
8 'base/js/dialog',
9 'base/js/events',
9 'base/js/events',
10 'base/js/keyboard',
10 'base/js/keyboard',
11 ], function(IPython, $, utils, dialog, events, keyboard) {
11 ], function(IPython, $, utils, dialog, events, keyboard) {
12 "use strict";
12 "use strict";
13
13
14 var NotebookList = function (selector, options) {
14 var NotebookList = function (selector, options) {
15 /**
15 /**
16 * Constructor
16 * Constructor
17 *
17 *
18 * Parameters:
18 * Parameters:
19 * selector: string
19 * selector: string
20 * options: dictionary
20 * options: dictionary
21 * Dictionary of keyword arguments.
21 * Dictionary of keyword arguments.
22 * session_list: SessionList instance
22 * session_list: SessionList instance
23 * element_name: string
23 * element_name: string
24 * base_url: string
24 * base_url: string
25 * notebook_path: string
25 * notebook_path: string
26 * contents: Contents instance
26 * contents: Contents instance
27 */
27 */
28 var that = this;
28 var that = this;
29 this.session_list = options.session_list;
29 this.session_list = options.session_list;
30 // allow code re-use by just changing element_name in kernellist.js
30 // allow code re-use by just changing element_name in kernellist.js
31 this.element_name = options.element_name || 'notebook';
31 this.element_name = options.element_name || 'notebook';
32 this.selector = selector;
32 this.selector = selector;
33 if (this.selector !== undefined) {
33 if (this.selector !== undefined) {
34 this.element = $(selector);
34 this.element = $(selector);
35 this.style();
35 this.style();
36 this.bind_events();
36 this.bind_events();
37 }
37 }
38 this.notebooks_list = [];
38 this.notebooks_list = [];
39 this.sessions = {};
39 this.sessions = {};
40 this.base_url = options.base_url || utils.get_body_data("baseUrl");
40 this.base_url = options.base_url || utils.get_body_data("baseUrl");
41 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
41 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
42 this.contents = options.contents;
42 this.contents = options.contents;
43 if (this.session_list && this.session_list.events) {
43 if (this.session_list && this.session_list.events) {
44 this.session_list.events.on('sessions_loaded.Dashboard',
44 this.session_list.events.on('sessions_loaded.Dashboard',
45 function(e, d) { that.sessions_loaded(d); });
45 function(e, d) { that.sessions_loaded(d); });
46 }
46 }
47 };
47 };
48
48
49 NotebookList.prototype.style = function () {
49 NotebookList.prototype.style = function () {
50 var prefix = '#' + this.element_name;
50 var prefix = '#' + this.element_name;
51 $(prefix + '_toolbar').addClass('list_toolbar');
51 $(prefix + '_toolbar').addClass('list_toolbar');
52 $(prefix + '_list_info').addClass('toolbar_info');
52 $(prefix + '_list_info').addClass('toolbar_info');
53 $(prefix + '_buttons').addClass('toolbar_buttons');
53 $(prefix + '_buttons').addClass('toolbar_buttons');
54 $(prefix + '_list_header').addClass('list_header');
54 $(prefix + '_list_header').addClass('list_header');
55 this.element.addClass("list_container");
55 this.element.addClass("list_container");
56 };
56 };
57
57
58 NotebookList.prototype.bind_events = function () {
58 NotebookList.prototype.bind_events = function () {
59 var that = this;
59 var that = this;
60 $('#refresh_' + this.element_name + '_list').click(function () {
60 $('#refresh_' + this.element_name + '_list').click(function () {
61 that.load_sessions();
61 that.load_sessions();
62 });
62 });
63 this.element.bind('dragover', function () {
63 this.element.bind('dragover', function () {
64 return false;
64 return false;
65 });
65 });
66 this.element.bind('drop', function(event){
66 this.element.bind('drop', function(event){
67 that.handleFilesUpload(event,'drop');
67 that.handleFilesUpload(event,'drop');
68 return false;
68 return false;
69 });
69 });
70
70
71 // Bind events for singleton controls.
71 // Bind events for singleton controls.
72 if (!NotebookList._bound_singletons) {
72 if (!NotebookList._bound_singletons) {
73 NotebookList._bound_singletons = true;
73 NotebookList._bound_singletons = true;
74 $('#new-file').click(function(e) {
74 $('#new-file').click(function(e) {
75 that._prompt_name('File').then(function(name) {
75 that.contents.new_untitled(that.notebook_path || '', {type: 'file', ext: '.txt'});
76 that._create('file', name).then(function() {
76 that.load_sessions();
77 that.load_sessions();
78 });
79 });
80 });
77 });
81 $('#new-folder').click(function(e) {
78 $('#new-folder').click(function(e) {
82 that._prompt_name('Folder').then(function(name) {
79 that.contents.new_untitled(that.notebook_path || '', {type: 'directory'});
83 that._create('directory', name).then(function() {
80 that.load_sessions();
84 that.load_sessions();
85 });
86 });
87 });
81 });
88 }
82 }
89 };
83 };
90
84
91 NotebookList.prototype.handleFilesUpload = function(event, dropOrForm) {
85 NotebookList.prototype.handleFilesUpload = function(event, dropOrForm) {
92 var that = this;
86 var that = this;
93 var files;
87 var files;
94 if(dropOrForm =='drop'){
88 if(dropOrForm =='drop'){
95 files = event.originalEvent.dataTransfer.files;
89 files = event.originalEvent.dataTransfer.files;
96 } else
90 } else
97 {
91 {
98 files = event.originalEvent.target.files;
92 files = event.originalEvent.target.files;
99 }
93 }
100 for (var i = 0; i < files.length; i++) {
94 for (var i = 0; i < files.length; i++) {
101 var f = files[i];
95 var f = files[i];
102 var name_and_ext = utils.splitext(f.name);
96 var name_and_ext = utils.splitext(f.name);
103 var file_ext = name_and_ext[1];
97 var file_ext = name_and_ext[1];
104
98
105 var reader = new FileReader();
99 var reader = new FileReader();
106 if (file_ext === '.ipynb') {
100 if (file_ext === '.ipynb') {
107 reader.readAsText(f);
101 reader.readAsText(f);
108 } else {
102 } else {
109 // read non-notebook files as binary
103 // read non-notebook files as binary
110 reader.readAsArrayBuffer(f);
104 reader.readAsArrayBuffer(f);
111 }
105 }
112 var item = that.new_item(0);
106 var item = that.new_item(0);
113 item.addClass('new-file');
107 item.addClass('new-file');
114 that.add_name_input(f.name, item, file_ext == '.ipynb' ? 'notebook' : 'file');
108 that.add_name_input(f.name, item, file_ext == '.ipynb' ? 'notebook' : 'file');
115 // Store the list item in the reader so we can use it later
109 // Store the list item in the reader so we can use it later
116 // to know which item it belongs to.
110 // to know which item it belongs to.
117 $(reader).data('item', item);
111 $(reader).data('item', item);
118 reader.onload = function (event) {
112 reader.onload = function (event) {
119 var item = $(event.target).data('item');
113 var item = $(event.target).data('item');
120 that.add_file_data(event.target.result, item);
114 that.add_file_data(event.target.result, item);
121 that.add_upload_button(item);
115 that.add_upload_button(item);
122 };
116 };
123 reader.onerror = function (event) {
117 reader.onerror = function (event) {
124 var item = $(event.target).data('item');
118 var item = $(event.target).data('item');
125 var name = item.data('name');
119 var name = item.data('name');
126 item.remove();
120 item.remove();
127 dialog.modal({
121 dialog.modal({
128 title : 'Failed to read file',
122 title : 'Failed to read file',
129 body : "Failed to read file '" + name + "'",
123 body : "Failed to read file '" + name + "'",
130 buttons : {'OK' : { 'class' : 'btn-primary' }}
124 buttons : {'OK' : { 'class' : 'btn-primary' }}
131 });
125 });
132 };
126 };
133 }
127 }
134 // Replace the file input form wth a clone of itself. This is required to
128 // Replace the file input form wth a clone of itself. This is required to
135 // reset the form. Otherwise, if you upload a file, delete it and try to
129 // reset the form. Otherwise, if you upload a file, delete it and try to
136 // upload it again, the changed event won't fire.
130 // upload it again, the changed event won't fire.
137 var form = $('input.fileinput');
131 var form = $('input.fileinput');
138 form.replaceWith(form.clone(true));
132 form.replaceWith(form.clone(true));
139 return false;
133 return false;
140 };
134 };
141
135
142 NotebookList.prototype.clear_list = function (remove_uploads) {
136 NotebookList.prototype.clear_list = function (remove_uploads) {
143 /**
137 /**
144 * Clears the navigation tree.
138 * Clears the navigation tree.
145 *
139 *
146 * Parameters
140 * Parameters
147 * remove_uploads: bool=False
141 * remove_uploads: bool=False
148 * Should upload prompts also be removed from the tree.
142 * Should upload prompts also be removed from the tree.
149 */
143 */
150 if (remove_uploads) {
144 if (remove_uploads) {
151 this.element.children('.list_item').remove();
145 this.element.children('.list_item').remove();
152 } else {
146 } else {
153 this.element.children('.list_item:not(.new-file)').remove();
147 this.element.children('.list_item:not(.new-file)').remove();
154 }
148 }
155 };
149 };
156
150
157 NotebookList.prototype.load_sessions = function(){
151 NotebookList.prototype.load_sessions = function(){
158 this.session_list.load_sessions();
152 this.session_list.load_sessions();
159 };
153 };
160
154
161
155
162 NotebookList.prototype.sessions_loaded = function(data){
156 NotebookList.prototype.sessions_loaded = function(data){
163 this.sessions = data;
157 this.sessions = data;
164 this.load_list();
158 this.load_list();
165 };
159 };
166
160
167 NotebookList.prototype.load_list = function () {
161 NotebookList.prototype.load_list = function () {
168 var that = this;
162 var that = this;
169 this.contents.list_contents(that.notebook_path).then(
163 this.contents.list_contents(that.notebook_path).then(
170 $.proxy(this.draw_notebook_list, this),
164 $.proxy(this.draw_notebook_list, this),
171 function(error) {
165 function(error) {
172 that.draw_notebook_list({content: []}, "Server error: " + error.message);
166 that.draw_notebook_list({content: []}, "Server error: " + error.message);
173 }
167 }
174 );
168 );
175 };
169 };
176
170
177 /**
171 /**
178 * Draw the list of notebooks
172 * Draw the list of notebooks
179 * @method draw_notebook_list
173 * @method draw_notebook_list
180 * @param {Array} list An array of dictionaries representing files or
174 * @param {Array} list An array of dictionaries representing files or
181 * directories.
175 * directories.
182 * @param {String} error_msg An error message
176 * @param {String} error_msg An error message
183 */
177 */
184
178
185
179
186 var type_order = {'directory':0,'notebook':1,'file':2};
180 var type_order = {'directory':0,'notebook':1,'file':2};
187
181
188 NotebookList.prototype.draw_notebook_list = function (list, error_msg) {
182 NotebookList.prototype.draw_notebook_list = function (list, error_msg) {
189 list.content.sort(function(a, b) {
183 list.content.sort(function(a, b) {
190 if (type_order[a['type']] < type_order[b['type']]) {
184 if (type_order[a['type']] < type_order[b['type']]) {
191 return -1;
185 return -1;
192 }
186 }
193 if (type_order[a['type']] > type_order[b['type']]) {
187 if (type_order[a['type']] > type_order[b['type']]) {
194 return 1;
188 return 1;
195 }
189 }
196 if (a['name'] < b['name']) {
190 if (a['name'] < b['name']) {
197 return -1;
191 return -1;
198 }
192 }
199 if (a['name'] > b['name']) {
193 if (a['name'] > b['name']) {
200 return 1;
194 return 1;
201 }
195 }
202 return 0;
196 return 0;
203 });
197 });
204 var message = error_msg || 'Notebook list empty.';
198 var message = error_msg || 'Notebook list empty.';
205 var item = null;
199 var item = null;
206 var model = null;
200 var model = null;
207 var len = list.content.length;
201 var len = list.content.length;
208 this.clear_list();
202 this.clear_list();
209 var n_uploads = this.element.children('.list_item').length;
203 var n_uploads = this.element.children('.list_item').length;
210 if (len === 0) {
204 if (len === 0) {
211 item = this.new_item(0);
205 item = this.new_item(0);
212 var span12 = item.children().first();
206 var span12 = item.children().first();
213 span12.empty();
207 span12.empty();
214 span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
208 span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
215 }
209 }
216 var path = this.notebook_path;
210 var path = this.notebook_path;
217 var offset = n_uploads;
211 var offset = n_uploads;
218 if (path !== '') {
212 if (path !== '') {
219 item = this.new_item(offset);
213 item = this.new_item(offset);
220 model = {
214 model = {
221 type: 'directory',
215 type: 'directory',
222 name: '..',
216 name: '..',
223 path: utils.url_path_split(path)[0],
217 path: utils.url_path_split(path)[0],
224 };
218 };
225 this.add_link(model, item);
219 this.add_link(model, item);
226 offset += 1;
220 offset += 1;
227 }
221 }
228 for (var i=0; i<len; i++) {
222 for (var i=0; i<len; i++) {
229 model = list.content[i];
223 model = list.content[i];
230 item = this.new_item(i+offset);
224 item = this.new_item(i+offset);
231 this.add_link(model, item);
225 this.add_link(model, item);
232 }
226 }
233 // Trigger an event when we've finished drawing the notebook list.
227 // Trigger an event when we've finished drawing the notebook list.
234 events.trigger('draw_notebook_list.NotebookList');
228 events.trigger('draw_notebook_list.NotebookList');
235 };
229 };
236
230
237
231
238 NotebookList.prototype.new_item = function (index) {
232 NotebookList.prototype.new_item = function (index) {
239 var item = $('<div/>').addClass("list_item").addClass("row");
233 var item = $('<div/>').addClass("list_item").addClass("row");
240 // item.addClass('list_item ui-widget ui-widget-content ui-helper-clearfix');
234 // item.addClass('list_item ui-widget ui-widget-content ui-helper-clearfix');
241 // item.css('border-top-style','none');
235 // item.css('border-top-style','none');
242 item.append($("<div/>").addClass("col-md-12").append(
236 item.append($("<div/>").addClass("col-md-12").append(
243 $('<i/>').addClass('item_icon')
237 $('<i/>').addClass('item_icon')
244 ).append(
238 ).append(
245 $("<a/>").addClass("item_link").append(
239 $("<a/>").addClass("item_link").append(
246 $("<span/>").addClass("item_name")
240 $("<span/>").addClass("item_name")
247 )
241 )
248 ).append(
242 ).append(
249 $('<div/>').addClass("item_buttons pull-right")
243 $('<div/>').addClass("item_buttons pull-right")
250 ));
244 ));
251
245
252 if (index === -1) {
246 if (index === -1) {
253 this.element.append(item);
247 this.element.append(item);
254 } else {
248 } else {
255 this.element.children().eq(index).after(item);
249 this.element.children().eq(index).after(item);
256 }
250 }
257 return item;
251 return item;
258 };
252 };
259
253
260
254
261 NotebookList.icons = {
255 NotebookList.icons = {
262 directory: 'folder_icon',
256 directory: 'folder_icon',
263 notebook: 'notebook_icon',
257 notebook: 'notebook_icon',
264 file: 'file_icon',
258 file: 'file_icon',
265 };
259 };
266
260
267 NotebookList.uri_prefixes = {
261 NotebookList.uri_prefixes = {
268 directory: 'tree',
262 directory: 'tree',
269 notebook: 'notebooks',
263 notebook: 'notebooks',
270 file: 'edit',
264 file: 'edit',
271 };
265 };
272
266
273
267
274 NotebookList.prototype.add_link = function (model, item) {
268 NotebookList.prototype.add_link = function (model, item) {
275 var path = model.path,
269 var path = model.path,
276 name = model.name;
270 name = model.name;
277 item.data('name', name);
271 item.data('name', name);
278 item.data('path', path);
272 item.data('path', path);
279 item.find(".item_name").text(name);
273 item.find(".item_name").text(name);
280 var icon = NotebookList.icons[model.type];
274 var icon = NotebookList.icons[model.type];
281 var uri_prefix = NotebookList.uri_prefixes[model.type];
275 var uri_prefix = NotebookList.uri_prefixes[model.type];
282 item.find(".item_icon").addClass(icon).addClass('icon-fixed-width');
276 item.find(".item_icon").addClass(icon).addClass('icon-fixed-width');
283 var link = item.find("a.item_link")
277 var link = item.find("a.item_link")
284 .attr('href',
278 .attr('href',
285 utils.url_join_encode(
279 utils.url_join_encode(
286 this.base_url,
280 this.base_url,
287 uri_prefix,
281 uri_prefix,
288 path
282 path
289 )
283 )
290 );
284 );
291 // directory nav doesn't open new tabs
285 // directory nav doesn't open new tabs
292 // files, notebooks do
286 // files, notebooks do
293 if (model.type !== "directory") {
287 if (model.type !== "directory") {
294 link.attr('target','_blank');
288 link.attr('target','_blank');
295 }
289 }
296 if (model.type !== 'directory') {
290 if (model.type !== 'directory') {
297 this.add_duplicate_button(item);
291 this.add_duplicate_button(item);
298 }
292 }
299 if (model.type == 'file') {
293 if (model.type == 'file') {
300 this.add_delete_button(item);
294 this.add_delete_button(item);
301 } else if (model.type == 'notebook') {
295 } else if (model.type == 'notebook') {
302 if (this.sessions[path] === undefined){
296 if (this.sessions[path] === undefined){
303 this.add_delete_button(item);
297 this.add_delete_button(item);
304 } else {
298 } else {
305 this.add_shutdown_button(item, this.sessions[path]);
299 this.add_shutdown_button(item, this.sessions[path]);
306 }
300 }
307 }
301 }
308 };
302 };
309
303
310
304
311 NotebookList.prototype.add_name_input = function (name, item, icon_type) {
305 NotebookList.prototype.add_name_input = function (name, item, icon_type) {
312 item.data('name', name);
306 item.data('name', name);
313 item.find(".item_icon").addClass(NotebookList.icons[icon_type]).addClass('icon-fixed-width');
307 item.find(".item_icon").addClass(NotebookList.icons[icon_type]).addClass('icon-fixed-width');
314 item.find(".item_name").empty().append(
308 item.find(".item_name").empty().append(
315 $('<input/>')
309 $('<input/>')
316 .addClass("filename_input")
310 .addClass("filename_input")
317 .attr('value', name)
311 .attr('value', name)
318 .attr('size', '30')
312 .attr('size', '30')
319 .attr('type', 'text')
313 .attr('type', 'text')
320 .keyup(function(event){
314 .keyup(function(event){
321 if(event.keyCode == 13){item.find('.upload_button').click();}
315 if(event.keyCode == 13){item.find('.upload_button').click();}
322 else if(event.keyCode == 27){item.remove();}
316 else if(event.keyCode == 27){item.remove();}
323 })
317 })
324 );
318 );
325 };
319 };
326
320
327
321
328 NotebookList.prototype.add_file_data = function (data, item) {
322 NotebookList.prototype.add_file_data = function (data, item) {
329 item.data('filedata', data);
323 item.data('filedata', data);
330 };
324 };
331
325
332
326
333 NotebookList.prototype.add_shutdown_button = function (item, session) {
327 NotebookList.prototype.add_shutdown_button = function (item, session) {
334 var that = this;
328 var that = this;
335 var shutdown_button = $("<button/>").text("Shutdown").addClass("btn btn-xs btn-warning").
329 var shutdown_button = $("<button/>").text("Shutdown").addClass("btn btn-xs btn-warning").
336 click(function (e) {
330 click(function (e) {
337 var settings = {
331 var settings = {
338 processData : false,
332 processData : false,
339 cache : false,
333 cache : false,
340 type : "DELETE",
334 type : "DELETE",
341 dataType : "json",
335 dataType : "json",
342 success : function () {
336 success : function () {
343 that.load_sessions();
337 that.load_sessions();
344 },
338 },
345 error : utils.log_ajax_error,
339 error : utils.log_ajax_error,
346 };
340 };
347 var url = utils.url_join_encode(
341 var url = utils.url_join_encode(
348 that.base_url,
342 that.base_url,
349 'api/sessions',
343 'api/sessions',
350 session
344 session
351 );
345 );
352 $.ajax(url, settings);
346 $.ajax(url, settings);
353 return false;
347 return false;
354 });
348 });
355 item.find(".item_buttons").append(shutdown_button);
349 item.find(".item_buttons").append(shutdown_button);
356 };
350 };
357
351
358 NotebookList.prototype.add_duplicate_button = function (item) {
352 NotebookList.prototype.add_duplicate_button = function (item) {
359 var notebooklist = this;
353 var notebooklist = this;
360 var duplicate_button = $("<button/>").text("Duplicate").addClass("btn btn-default btn-xs").
354 var duplicate_button = $("<button/>").text("Duplicate").addClass("btn btn-default btn-xs").
361 click(function (e) {
355 click(function (e) {
362 // $(this) is the button that was clicked.
356 // $(this) is the button that was clicked.
363 var that = $(this);
357 var that = $(this);
364 var name = item.data('name');
358 var name = item.data('name');
365 var path = item.data('path');
359 var path = item.data('path');
366 var message = 'Are you sure you want to duplicate ' + name + '?';
360 var message = 'Are you sure you want to duplicate ' + name + '?';
367 var copy_from = {copy_from : path};
361 var copy_from = {copy_from : path};
368 IPython.dialog.modal({
362 IPython.dialog.modal({
369 title : "Duplicate " + name,
363 title : "Duplicate " + name,
370 body : message,
364 body : message,
371 buttons : {
365 buttons : {
372 Duplicate : {
366 Duplicate : {
373 class: "btn-primary",
367 class: "btn-primary",
374 click: function() {
368 click: function() {
375 notebooklist.contents.copy(path, notebooklist.notebook_path).then(function () {
369 notebooklist.contents.copy(path, notebooklist.notebook_path).then(function () {
376 notebooklist.load_list();
370 notebooklist.load_list();
377 });
371 });
378 }
372 }
379 },
373 },
380 Cancel : {}
374 Cancel : {}
381 }
375 }
382 });
376 });
383 return false;
377 return false;
384 });
378 });
385 item.find(".item_buttons").append(duplicate_button);
379 item.find(".item_buttons").append(duplicate_button);
386 };
380 };
387
381
388 NotebookList.prototype.add_delete_button = function (item) {
382 NotebookList.prototype.add_delete_button = function (item) {
389 var notebooklist = this;
383 var notebooklist = this;
390 var delete_button = $("<button/>").text("Delete").addClass("btn btn-default btn-xs").
384 var delete_button = $("<button/>").text("Delete").addClass("btn btn-default btn-xs").
391 click(function (e) {
385 click(function (e) {
392 // $(this) is the button that was clicked.
386 // $(this) is the button that was clicked.
393 var that = $(this);
387 var that = $(this);
394 // We use the filename from the parent list_item element's
388 // We use the filename from the parent list_item element's
395 // data because the outer scope's values change as we iterate through the loop.
389 // data because the outer scope's values change as we iterate through the loop.
396 var parent_item = that.parents('div.list_item');
390 var parent_item = that.parents('div.list_item');
397 var name = parent_item.data('name');
391 var name = parent_item.data('name');
398 var path = parent_item.data('path');
392 var path = parent_item.data('path');
399 var message = 'Are you sure you want to permanently delete the file: ' + name + '?';
393 var message = 'Are you sure you want to permanently delete the file: ' + name + '?';
400 dialog.modal({
394 dialog.modal({
401 title : "Delete file",
395 title : "Delete file",
402 body : message,
396 body : message,
403 buttons : {
397 buttons : {
404 Delete : {
398 Delete : {
405 class: "btn-danger",
399 class: "btn-danger",
406 click: function() {
400 click: function() {
407 notebooklist.contents.delete(path).then(
401 notebooklist.contents.delete(path).then(
408 function() {
402 function() {
409 notebooklist.notebook_deleted(path);
403 notebooklist.notebook_deleted(path);
410 }
404 }
411 );
405 );
412 }
406 }
413 },
407 },
414 Cancel : {}
408 Cancel : {}
415 }
409 }
416 });
410 });
417 return false;
411 return false;
418 });
412 });
419 item.find(".item_buttons").append(delete_button);
413 item.find(".item_buttons").append(delete_button);
420 };
414 };
421
415
422 NotebookList.prototype.notebook_deleted = function(path) {
416 NotebookList.prototype.notebook_deleted = function(path) {
423 /**
417 /**
424 * Remove the deleted notebook.
418 * Remove the deleted notebook.
425 */
419 */
426 $( ":data(path)" ).each(function() {
420 $( ":data(path)" ).each(function() {
427 var element = $(this);
421 var element = $(this);
428 if (element.data("path") == path) {
422 if (element.data("path") == path) {
429 element.remove();
423 element.remove();
430 events.trigger('notebook_deleted.NotebookList');
424 events.trigger('notebook_deleted.NotebookList');
431 }
425 }
432 });
426 });
433 };
427 };
434
428
435
429
436 NotebookList.prototype.add_upload_button = function (item) {
430 NotebookList.prototype.add_upload_button = function (item) {
437 var that = this;
431 var that = this;
438 var upload_button = $('<button/>').text("Upload")
432 var upload_button = $('<button/>').text("Upload")
439 .addClass('btn btn-primary btn-xs upload_button')
433 .addClass('btn btn-primary btn-xs upload_button')
440 .click(function (e) {
434 .click(function (e) {
441 var filename = item.find('.item_name > input').val();
435 var filename = item.find('.item_name > input').val();
442 var path = utils.url_path_join(that.notebook_path, filename);
436 var path = utils.url_path_join(that.notebook_path, filename);
443 var filedata = item.data('filedata');
437 var filedata = item.data('filedata');
444 var format = 'text';
438 var format = 'text';
445 if (filename.length === 0 || filename[0] === '.') {
439 if (filename.length === 0 || filename[0] === '.') {
446 dialog.modal({
440 dialog.modal({
447 title : 'Invalid file name',
441 title : 'Invalid file name',
448 body : "File names must be at least one character and not start with a dot",
442 body : "File names must be at least one character and not start with a dot",
449 buttons : {'OK' : { 'class' : 'btn-primary' }}
443 buttons : {'OK' : { 'class' : 'btn-primary' }}
450 });
444 });
451 return false;
445 return false;
452 }
446 }
453 if (filedata instanceof ArrayBuffer) {
447 if (filedata instanceof ArrayBuffer) {
454 // base64-encode binary file data
448 // base64-encode binary file data
455 var bytes = '';
449 var bytes = '';
456 var buf = new Uint8Array(filedata);
450 var buf = new Uint8Array(filedata);
457 var nbytes = buf.byteLength;
451 var nbytes = buf.byteLength;
458 for (var i=0; i<nbytes; i++) {
452 for (var i=0; i<nbytes; i++) {
459 bytes += String.fromCharCode(buf[i]);
453 bytes += String.fromCharCode(buf[i]);
460 }
454 }
461 filedata = btoa(bytes);
455 filedata = btoa(bytes);
462 format = 'base64';
456 format = 'base64';
463 }
457 }
464 var model = {};
458 var model = {};
465
459
466 var name_and_ext = utils.splitext(filename);
460 var name_and_ext = utils.splitext(filename);
467 var file_ext = name_and_ext[1];
461 var file_ext = name_and_ext[1];
468 var content_type;
462 var content_type;
469 if (file_ext === '.ipynb') {
463 if (file_ext === '.ipynb') {
470 model.type = 'notebook';
464 model.type = 'notebook';
471 model.format = 'json';
465 model.format = 'json';
472 try {
466 try {
473 model.content = JSON.parse(filedata);
467 model.content = JSON.parse(filedata);
474 } catch (e) {
468 } catch (e) {
475 dialog.modal({
469 dialog.modal({
476 title : 'Cannot upload invalid Notebook',
470 title : 'Cannot upload invalid Notebook',
477 body : "The error was: " + e,
471 body : "The error was: " + e,
478 buttons : {'OK' : {
472 buttons : {'OK' : {
479 'class' : 'btn-primary',
473 'class' : 'btn-primary',
480 click: function () {
474 click: function () {
481 item.remove();
475 item.remove();
482 }
476 }
483 }}
477 }}
484 });
478 });
485 return false;
479 return false;
486 }
480 }
487 content_type = 'application/json';
481 content_type = 'application/json';
488 } else {
482 } else {
489 model.type = 'file';
483 model.type = 'file';
490 model.format = format;
484 model.format = format;
491 model.content = filedata;
485 model.content = filedata;
492 content_type = 'application/octet-stream';
486 content_type = 'application/octet-stream';
493 }
487 }
494 filedata = item.data('filedata');
488 filedata = item.data('filedata');
495
489
496 var on_success = function () {
490 var on_success = function () {
497 item.removeClass('new-file');
491 item.removeClass('new-file');
498 that.add_link(model, item);
492 that.add_link(model, item);
499 that.add_delete_button(item);
493 that.add_delete_button(item);
500 that.session_list.load_sessions();
494 that.session_list.load_sessions();
501 };
495 };
502
496
503 var exists = false;
497 var exists = false;
504 $.each(that.element.find('.list_item:not(.new-file)'), function(k,v){
498 $.each(that.element.find('.list_item:not(.new-file)'), function(k,v){
505 if ($(v).data('name') === filename) { exists = true; return false; }
499 if ($(v).data('name') === filename) { exists = true; return false; }
506 });
500 });
507
501
508 if (exists) {
502 if (exists) {
509 dialog.modal({
503 dialog.modal({
510 title : "Replace file",
504 title : "Replace file",
511 body : 'There is already a file named ' + filename + ', do you want to replace it?',
505 body : 'There is already a file named ' + filename + ', do you want to replace it?',
512 buttons : {
506 buttons : {
513 Overwrite : {
507 Overwrite : {
514 class: "btn-danger",
508 class: "btn-danger",
515 click: function () {
509 click: function () {
516 that.contents.save(path, model).then(on_success);
510 that.contents.save(path, model).then(on_success);
517 }
511 }
518 },
512 },
519 Cancel : {
513 Cancel : {
520 click: function() { item.remove(); }
514 click: function() { item.remove(); }
521 }
515 }
522 }
516 }
523 });
517 });
524 } else {
518 } else {
525 that.contents.save(path, model).then(on_success);
519 that.contents.save(path, model).then(on_success);
526 }
520 }
527
521
528 return false;
522 return false;
529 });
523 });
530 var cancel_button = $('<button/>').text("Cancel")
524 var cancel_button = $('<button/>').text("Cancel")
531 .addClass("btn btn-default btn-xs")
525 .addClass("btn btn-default btn-xs")
532 .click(function (e) {
526 .click(function (e) {
533 item.remove();
527 item.remove();
534 return false;
528 return false;
535 });
529 });
536 item.find(".item_buttons").empty()
530 item.find(".item_buttons").empty()
537 .append(upload_button)
531 .append(upload_button)
538 .append(cancel_button);
532 .append(cancel_button);
539 };
533 };
540
534
541 /**
542 * Prompt the user for a name.
543 * @param {string} what - What you want a name for.
544 * @return {Promise} Promise that resolve with a string name
545 */
546 NotebookList.prototype._prompt_name = function(what) {
547 var that = this;
548 var dialog_body = $('<div/>').append(
549 $("<p/>").addClass("rename-message")
550 .text(what + ' name:')
551 ).append(
552 $("<br/>")
553 ).append(
554 $('<input/>').attr('type','text').attr('size','25').addClass('form-control')
555 .val('') // Default to empty
556 );
557
558 return new Promise(function(resolve, reject) {
559 var dialog_inst = dialog.modal({
560 title: "Rename Notebook",
561 body: dialog_body,
562 buttons: {
563 "OK": {
564 class: "btn-primary",
565 click: function () {
566 resolve(dialog_inst.find('input').val());
567 }
568 },
569 "Cancel": {
570 click: function () {
571 reject();
572 }
573 }
574 }, open: function () {
575 /**
576 * Upon ENTER, click the OK button.
577 */
578 dialog_inst.find('input[type="text"]').keydown(function (event) {
579 if (event.which === keyboard.keycodes.enter) {
580 dialog_inst.find('.btn-primary').first().click();
581 return false;
582 }
583 });
584 dialog_inst.find('input[type="text"]').focus().select();
585 }
586 });
587 });
588 };
589
590 /**
591 * Creates a `file` or `directory`
592 * @param {string} type - "file" or "directory"
593 * @param {string} name - name of the thing to create
594 * @return {Promise} success
595 */
596 NotebookList.prototype._create = function(type, name) {
597 var that = this;
598 return new Promise(function(resolve, reject) {
599 var settings = {
600 processData : false,
601 cache : false,
602 type : "PUT",
603 data: JSON.stringify({
604 type: type,
605 format: 'text',
606 content: '',
607 }),
608 dataType: "json",
609 success: function () {
610 resolve();
611 },
612 error: function() {
613 reject();
614 utils.log_ajax_error.apply(this, arguments);
615 },
616 };
617 var url = utils.url_join_encode(
618 that.base_url,
619 'api/contents/' + name
620 );
621 $.ajax(url, settings);
622 });
623 };
624
625
535
626 // Backwards compatability.
536 // Backwards compatability.
627 IPython.NotebookList = NotebookList;
537 IPython.NotebookList = NotebookList;
628
538
629 return {'NotebookList': NotebookList};
539 return {'NotebookList': NotebookList};
630 });
540 });
General Comments 0
You need to be logged in to leave comments. Login now