##// END OF EJS Templates
Merge pull request #7662 from jdfreder/autorefreshfix...
Min RK -
r20307:9acc2519 merge
parent child Browse files
Show More
@@ -1,771 +1,787 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 'base/js/namespace',
6 6 'jquery',
7 7 'base/js/utils',
8 8 'base/js/dialog',
9 9 'base/js/events',
10 10 'base/js/keyboard',
11 11 ], function(IPython, $, utils, dialog, events, keyboard) {
12 12 "use strict";
13 13
14 14 var NotebookList = function (selector, options) {
15 15 /**
16 16 * Constructor
17 17 *
18 18 * Parameters:
19 19 * selector: string
20 20 * options: dictionary
21 21 * Dictionary of keyword arguments.
22 22 * session_list: SessionList instance
23 23 * element_name: string
24 24 * base_url: string
25 25 * notebook_path: string
26 26 * contents: Contents instance
27 27 */
28 28 var that = this;
29 29 this.session_list = options.session_list;
30 30 // allow code re-use by just changing element_name in kernellist.js
31 31 this.element_name = options.element_name || 'notebook';
32 32 this.selector = selector;
33 33 if (this.selector !== undefined) {
34 34 this.element = $(selector);
35 35 this.style();
36 36 this.bind_events();
37 37 }
38 38 this.notebooks_list = [];
39 39 this.sessions = {};
40 40 this.base_url = options.base_url || utils.get_body_data("baseUrl");
41 41 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
42 42 this.contents = options.contents;
43 43 if (this.session_list && this.session_list.events) {
44 44 this.session_list.events.on('sessions_loaded.Dashboard',
45 45 function(e, d) { that.sessions_loaded(d); });
46 46 }
47 47 };
48 48
49 49 NotebookList.prototype.style = function () {
50 50 var prefix = '#' + this.element_name;
51 51 $(prefix + '_toolbar').addClass('list_toolbar');
52 52 $(prefix + '_list_info').addClass('toolbar_info');
53 53 $(prefix + '_buttons').addClass('toolbar_buttons');
54 54 $(prefix + '_list_header').addClass('list_header');
55 55 this.element.addClass("list_container");
56 56 };
57 57
58 58 NotebookList.prototype.bind_events = function () {
59 59 var that = this;
60 60 $('#refresh_' + this.element_name + '_list').click(function () {
61 61 that.load_sessions();
62 62 });
63 63 this.element.bind('dragover', function () {
64 64 return false;
65 65 });
66 66 this.element.bind('drop', function(event){
67 67 that.handleFilesUpload(event,'drop');
68 68 return false;
69 69 });
70 70
71 71 // Bind events for singleton controls.
72 72 if (!NotebookList._bound_singletons) {
73 73 NotebookList._bound_singletons = true;
74 74 $('#new-file').click(function(e) {
75 75 var w = window.open();
76 76 that.contents.new_untitled(that.notebook_path || '', {type: 'file', ext: '.txt'}).then(function(data) {
77 77 var url = utils.url_join_encode(
78 78 that.base_url, 'edit', data.path
79 79 );
80 80 w.location = url;
81 81 }).catch(function (e) {
82 82 w.close();
83 83 dialog.modal({
84 84 title: 'Creating File Failed',
85 85 body: $('<div/>')
86 86 .text("An error occurred while creating a new file.")
87 87 .append($('<div/>')
88 88 .addClass('alert alert-danger')
89 89 .text(e.message || e)),
90 90 buttons: {
91 91 OK: {'class': 'btn-primary'}
92 92 }
93 93 });
94 94 });
95 95 that.load_sessions();
96 96 });
97 97 $('#new-folder').click(function(e) {
98 98 that.contents.new_untitled(that.notebook_path || '', {type: 'directory'})
99 99 .then(function(){
100 100 that.load_list();
101 101 }).catch(function (e) {
102 102 dialog.modal({
103 103 title: 'Creating Folder Failed',
104 104 body: $('<div/>')
105 105 .text("An error occurred while creating a new folder.")
106 106 .append($('<div/>')
107 107 .addClass('alert alert-danger')
108 108 .text(e.message || e)),
109 109 buttons: {
110 110 OK: {'class': 'btn-primary'}
111 111 }
112 112 });
113 113 });
114 114 that.load_sessions();
115 115 });
116 116
117 117 $('.rename-button').click($.proxy(this.rename_selected, this));
118 118 $('.shutdown-button').click($.proxy(this.shutdown_selected, this));
119 119 $('.duplicate-button').click($.proxy(this.duplicate_selected, this));
120 120 $('.delete-button').click($.proxy(this.delete_selected, this));
121 121 }
122 122 };
123 123
124 124 NotebookList.prototype.handleFilesUpload = function(event, dropOrForm) {
125 125 var that = this;
126 126 var files;
127 127 if(dropOrForm =='drop'){
128 128 files = event.originalEvent.dataTransfer.files;
129 129 } else
130 130 {
131 131 files = event.originalEvent.target.files;
132 132 }
133 133 for (var i = 0; i < files.length; i++) {
134 134 var f = files[i];
135 135 var name_and_ext = utils.splitext(f.name);
136 136 var file_ext = name_and_ext[1];
137 137
138 138 var reader = new FileReader();
139 139 if (file_ext === '.ipynb') {
140 140 reader.readAsText(f);
141 141 } else {
142 142 // read non-notebook files as binary
143 143 reader.readAsArrayBuffer(f);
144 144 }
145 145 var item = that.new_item(0, true);
146 146 item.addClass('new-file');
147 147 that.add_name_input(f.name, item, file_ext == '.ipynb' ? 'notebook' : 'file');
148 148 // Store the list item in the reader so we can use it later
149 149 // to know which item it belongs to.
150 150 $(reader).data('item', item);
151 151 reader.onload = function (event) {
152 152 var item = $(event.target).data('item');
153 153 that.add_file_data(event.target.result, item);
154 154 that.add_upload_button(item);
155 155 };
156 156 reader.onerror = function (event) {
157 157 var item = $(event.target).data('item');
158 158 var name = item.data('name');
159 159 item.remove();
160 160 dialog.modal({
161 161 title : 'Failed to read file',
162 162 body : "Failed to read file '" + name + "'",
163 163 buttons : {'OK' : { 'class' : 'btn-primary' }}
164 164 });
165 165 };
166 166 }
167 167 // Replace the file input form wth a clone of itself. This is required to
168 168 // reset the form. Otherwise, if you upload a file, delete it and try to
169 169 // upload it again, the changed event won't fire.
170 170 var form = $('input.fileinput');
171 171 form.replaceWith(form.clone(true));
172 172 return false;
173 173 };
174 174
175 175 NotebookList.prototype.clear_list = function (remove_uploads) {
176 176 /**
177 177 * Clears the navigation tree.
178 178 *
179 179 * Parameters
180 180 * remove_uploads: bool=False
181 181 * Should upload prompts also be removed from the tree.
182 182 */
183 183 if (remove_uploads) {
184 184 this.element.children('.list_item').remove();
185 185 } else {
186 186 this.element.children('.list_item:not(.new-file)').remove();
187 187 }
188 188 };
189 189
190 190 NotebookList.prototype.load_sessions = function(){
191 191 this.session_list.load_sessions();
192 192 };
193 193
194 194
195 195 NotebookList.prototype.sessions_loaded = function(data){
196 196 this.sessions = data;
197 197 this.load_list();
198 198 };
199 199
200 200 NotebookList.prototype.load_list = function () {
201 201 var that = this;
202 202 this.contents.list_contents(that.notebook_path).then(
203 203 $.proxy(this.draw_notebook_list, this),
204 204 function(error) {
205 205 that.draw_notebook_list({content: []}, "Server error: " + error.message);
206 206 }
207 207 );
208 208 };
209 209
210 210 /**
211 211 * Draw the list of notebooks
212 212 * @method draw_notebook_list
213 213 * @param {Array} list An array of dictionaries representing files or
214 214 * directories.
215 215 * @param {String} error_msg An error message
216 216 */
217 217
218 218
219 219 var type_order = {'directory':0,'notebook':1,'file':2};
220 220
221 221 NotebookList.prototype.draw_notebook_list = function (list, error_msg) {
222 // Remember what was selected before the refresh.
223 var selected_before = this.selected;
224
222 225 list.content.sort(function(a, b) {
223 226 if (type_order[a['type']] < type_order[b['type']]) {
224 227 return -1;
225 228 }
226 229 if (type_order[a['type']] > type_order[b['type']]) {
227 230 return 1;
228 231 }
229 232 if (a['name'] < b['name']) {
230 233 return -1;
231 234 }
232 235 if (a['name'] > b['name']) {
233 236 return 1;
234 237 }
235 238 return 0;
236 239 });
237 240 var message = error_msg || 'Notebook list empty.';
238 241 var item = null;
239 242 var model = null;
240 243 var len = list.content.length;
241 244 this.clear_list();
242 245 var n_uploads = this.element.children('.list_item').length;
243 246 if (len === 0) {
244 247 item = this.new_item(0);
245 248 var span12 = item.children().first();
246 249 span12.empty();
247 250 span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
248 251 }
249 252 var path = this.notebook_path;
250 253 var offset = n_uploads;
251 254 if (path !== '') {
252 255 item = this.new_item(offset, false);
253 256 model = {
254 257 type: 'directory',
255 258 name: '..',
256 259 path: utils.url_path_split(path)[0],
257 260 };
258 261 this.add_link(model, item);
259 262 offset += 1;
260 263 }
261 264 for (var i=0; i<len; i++) {
262 265 model = list.content[i];
263 266 item = this.new_item(i+offset, true);
264 267 this.add_link(model, item);
265 268 }
266 269 // Trigger an event when we've finished drawing the notebook list.
267 270 events.trigger('draw_notebook_list.NotebookList');
268 this._selection_changed();
271
272 // Reselect the items that were selected before. Notify listeners
273 // that the selected items may have changed. O(n^2) operation.
274 selected_before.forEach(function(item) {
275 var list_items = $('.list_item');
276 for (var i=0; i<list_items.length; i++) {
277 var $list_item = $(list_items[i]);
278 if ($list_item.data('path') == item.path) {
279 $list_item.find('input[type=checkbox]').prop('checked', true);
280 break;
281 }
282 }
283 });
284 this._selection_changed();
269 285 };
270 286
271 287
272 288 /**
273 289 * Creates a new item.
274 290 * @param {integer} index
275 291 * @param {boolean} [selectable] - tristate, undefined: don't draw checkbox,
276 292 * false: don't draw checkbox but pad
277 293 * where it should be, true: draw checkbox.
278 294 * @return {JQuery} row
279 295 */
280 296 NotebookList.prototype.new_item = function (index, selectable) {
281 297 var row = $('<div/>')
282 298 .addClass("list_item")
283 299 .addClass("row");
284 300
285 301 var item = $("<div/>")
286 302 .addClass("col-md-12")
287 303 .appendTo(row);
288 304
289 305 var checkbox;
290 306 if (selectable !== undefined) {
291 307 checkbox = $('<input/>')
292 308 .attr('type', 'checkbox')
293 309 .attr('title', 'Click here to rename, delete, etc.')
294 310 .appendTo(item);
295 311 }
296 312
297 313 $('<i/>')
298 314 .addClass('item_icon')
299 315 .appendTo(item);
300 316
301 317 var link = $("<a/>")
302 318 .addClass("item_link")
303 319 .appendTo(item);
304 320
305 321 $("<span/>")
306 322 .addClass("item_name")
307 323 .appendTo(link);
308 324
309 325 if (selectable === false) {
310 326 checkbox.css('visibility', 'hidden');
311 327 } else if (selectable === true) {
312 328 var that = this;
313 329 link.click(function(e) {
314 330 e.stopPropagation();
315 331 });
316 332 checkbox.click(function(e) {
317 333 e.stopPropagation();
318 334 that._selection_changed();
319 335 });
320 336 row.click(function(e) {
321 337 e.stopPropagation();
322 338 checkbox.prop('checked', !checkbox.prop('checked'));
323 339 that._selection_changed();
324 340 });
325 341 }
326 342
327 343 var buttons = $('<div/>')
328 344 .addClass("item_buttons pull-right")
329 345 .appendTo(item);
330 346
331 347 $('<div/>')
332 348 .addClass('running-indicator')
333 349 .text('Running')
334 350 .css('visibility', 'hidden')
335 351 .appendTo(buttons);
336 352
337 353 if (index === -1) {
338 354 this.element.append(row);
339 355 } else {
340 356 this.element.children().eq(index).after(row);
341 357 }
342 358 return row;
343 359 };
344 360
345 361
346 362 NotebookList.icons = {
347 363 directory: 'folder_icon',
348 364 notebook: 'notebook_icon',
349 365 file: 'file_icon',
350 366 };
351 367
352 368 NotebookList.uri_prefixes = {
353 369 directory: 'tree',
354 370 notebook: 'notebooks',
355 371 file: 'edit',
356 372 };
357 373
358 374 /**
359 375 * Handles when any row selector checkbox is toggled.
360 376 */
361 377 NotebookList.prototype._selection_changed = function() {
362 378
363 379 // Use a JQuery selector to find each row with a checked checkbox. If
364 380 // we decide to add more checkboxes in the future, this code will need
365 381 // to be changed to distinguish which checkbox is the row selector.
366 382 var selected = [];
367 383 var has_running_notebook = false;
368 384 var has_directory = false;
369 385 var has_file = false;
370 386 var that = this;
371 387 $('.list_item :checked').each(function(index, item) {
372 388 var parent = $(item).parent().parent();
373 389
374 390 // If the item doesn't have an upload button, it can be selected.
375 391 if (parent.find('.upload_button').length === 0) {
376 392 selected.push({
377 393 name: parent.data('name'),
378 394 path: parent.data('path'),
379 395 type: parent.data('type')
380 396 });
381 397
382 398 // Set flags according to what is selected. Flags are later
383 399 // used to decide which action buttons are visible.
384 400 has_running_notebook = has_running_notebook ||
385 401 (parent.data('type') == 'notebook' && that.sessions[parent.data('path')] !== undefined);
386 402 has_file = has_file || parent.data('type') == 'file';
387 403 has_directory = has_directory || parent.data('type') == 'directory';
388 404 }
389 405 });
390 406 this.selected = selected;
391 407
392 408 // Rename is only visible when one item is selected.
393 409 if (selected.length==1) {
394 410 $('.rename-button').css('display', 'inline-block');
395 411 } else {
396 412 $('.rename-button').css('display', 'none');
397 413 }
398 414
399 415 // Shutdown is only visible when one or more notebooks running notebooks
400 416 // are selected and no non-notebook items are selected.
401 417 if (has_running_notebook && !(has_file || has_directory)) {
402 418 $('.shutdown-button').css('display', 'inline-block');
403 419 } else {
404 420 $('.shutdown-button').css('display', 'none');
405 421 }
406 422
407 423 // Duplicate isn't visible when a directory is selected.
408 424 if (selected.length > 0 && !has_directory) {
409 425 $('.duplicate-button').css('display', 'inline-block');
410 426 } else {
411 427 $('.duplicate-button').css('display', 'none');
412 428 }
413 429
414 430 // Delete is visible if one or more items are selected.
415 431 if (selected.length > 0) {
416 432 $('.delete-button').css('display', 'inline-block');
417 433 } else {
418 434 $('.delete-button').css('display', 'none');
419 435 }
420 436 };
421 437
422 438 NotebookList.prototype.add_link = function (model, item) {
423 439 var path = model.path,
424 440 name = model.name;
425 441 var running = (model.type == 'notebook' && this.sessions[path] !== undefined);
426 442
427 443 item.data('name', name);
428 444 item.data('path', path);
429 445 item.data('type', model.type);
430 446 item.find(".item_name").text(name);
431 447 var icon = NotebookList.icons[model.type];
432 448 if (running) {
433 449 icon = 'running_' + icon;
434 450 }
435 451 var uri_prefix = NotebookList.uri_prefixes[model.type];
436 452 item.find(".item_icon").addClass(icon).addClass('icon-fixed-width');
437 453 var link = item.find("a.item_link")
438 454 .attr('href',
439 455 utils.url_join_encode(
440 456 this.base_url,
441 457 uri_prefix,
442 458 path
443 459 )
444 460 );
445 461
446 462 item.find(".item_buttons .running-indicator").css('visibility', running ? '' : 'hidden');
447 463
448 464 // directory nav doesn't open new tabs
449 465 // files, notebooks do
450 466 if (model.type !== "directory") {
451 467 link.attr('target','_blank');
452 468 }
453 469 };
454 470
455 471
456 472 NotebookList.prototype.add_name_input = function (name, item, icon_type) {
457 473 item.data('name', name);
458 474 item.find(".item_icon").addClass(NotebookList.icons[icon_type]).addClass('icon-fixed-width');
459 475 item.find(".item_name").empty().append(
460 476 $('<input/>')
461 477 .addClass("filename_input")
462 478 .attr('value', name)
463 479 .attr('size', '30')
464 480 .attr('type', 'text')
465 481 .keyup(function(event){
466 482 if(event.keyCode == 13){item.find('.upload_button').click();}
467 483 else if(event.keyCode == 27){item.remove();}
468 484 })
469 485 );
470 486 };
471 487
472 488
473 489 NotebookList.prototype.add_file_data = function (data, item) {
474 490 item.data('filedata', data);
475 491 };
476 492
477 493
478 494 NotebookList.prototype.shutdown_selected = function() {
479 495 var that = this;
480 496 this.selected.forEach(function(item) {
481 497 if (item.type == 'notebook') {
482 498 that.shutdown_notebook(item.path);
483 499 }
484 500 });
485 501 };
486 502
487 503 NotebookList.prototype.shutdown_notebook = function(path) {
488 504 var that = this;
489 505 var settings = {
490 506 processData : false,
491 507 cache : false,
492 508 type : "DELETE",
493 509 dataType : "json",
494 510 success : function () {
495 511 that.load_sessions();
496 512 },
497 513 error : utils.log_ajax_error,
498 514 };
499 515
500 516 var session = this.sessions[path];
501 517 if (session) {
502 518 var url = utils.url_join_encode(
503 519 this.base_url,
504 520 'api/sessions',
505 521 session
506 522 );
507 523 $.ajax(url, settings);
508 524 }
509 525 };
510 526
511 527 NotebookList.prototype.rename_selected = function() {
512 528 if (this.selected.length != 1) return;
513 529
514 530 var that = this;
515 531 var path = this.selected[0].path;
516 532 var input = $('<input/>').attr('type','text').attr('size','25').addClass('form-control')
517 533 .val(path);
518 534 var dialog_body = $('<div/>').append(
519 535 $("<p/>").addClass("rename-message")
520 536 .text('Enter a new directory name:')
521 537 ).append(
522 538 $("<br/>")
523 539 ).append(input);
524 540 var d = dialog.modal({
525 541 title : "Rename directory",
526 542 body : dialog_body,
527 543 buttons : {
528 544 OK : {
529 545 class: "btn-primary",
530 546 click: function() {
531 547 that.contents.rename(path, input.val()).then(function() {
532 548 that.load_list();
533 549 }).catch(function(e) {
534 550 dialog.modal({
535 551 title: "Rename Failed",
536 552 body: $('<div/>')
537 553 .text("An error occurred while renaming \"" + path + "\" to \"" + input.val() + "\".")
538 554 .append($('<div/>')
539 555 .addClass('alert alert-danger')
540 556 .text(e.message || e)),
541 557 buttons: {
542 558 OK: {'class': 'btn-primary'}
543 559 }
544 560 });
545 561 });
546 562 }
547 563 },
548 564 Cancel : {}
549 565 },
550 566 open : function () {
551 567 // Upon ENTER, click the OK button.
552 568 input.keydown(function (event) {
553 569 if (event.which === keyboard.keycodes.enter) {
554 570 d.find('.btn-primary').first().click();
555 571 return false;
556 572 }
557 573 });
558 574 input.focus().select();
559 575 }
560 576 });
561 577 };
562 578
563 579 NotebookList.prototype.delete_selected = function() {
564 580 var message;
565 581 if (this.selected.length == 1) {
566 582 message = 'Are you sure you want to permanently delete: ' + this.selected[0].name + '?';
567 583 } else {
568 584 message = 'Are you sure you want to permanently delete the ' + this.selected.length + ' files/folders selected?';
569 585 }
570 586 var that = this;
571 587 dialog.modal({
572 588 title : "Delete",
573 589 body : message,
574 590 buttons : {
575 591 Delete : {
576 592 class: "btn-danger",
577 593 click: function() {
578 594 // Shutdown any/all selected notebooks before deleting
579 595 // the files.
580 596 that.shutdown_selected();
581 597
582 598 // Delete selected.
583 599 that.selected.forEach(function(item) {
584 600 that.contents.delete(item.path).then(function() {
585 601 that.notebook_deleted(item.path);
586 602 }).catch(function(e) {
587 603 dialog.modal({
588 604 title: "Delete Failed",
589 605 body: $('<div/>')
590 606 .text("An error occurred while deleting \"" + item.path + "\".")
591 607 .append($('<div/>')
592 608 .addClass('alert alert-danger')
593 609 .text(e.message || e)),
594 610 buttons: {
595 611 OK: {'class': 'btn-primary'}
596 612 }
597 613 });
598 614 });
599 615 });
600 616 }
601 617 },
602 618 Cancel : {}
603 619 }
604 620 });
605 621 };
606 622
607 623 NotebookList.prototype.duplicate_selected = function() {
608 624 var message;
609 625 if (this.selected.length == 1) {
610 626 message = 'Are you sure you want to duplicate: ' + this.selected[0].name + '?';
611 627 } else {
612 628 message = 'Are you sure you want to duplicate the ' + this.selected.length + ' files selected?';
613 629 }
614 630 var that = this;
615 631 dialog.modal({
616 632 title : "Delete",
617 633 body : message,
618 634 buttons : {
619 635 Duplicate : {
620 636 class: "btn-primary",
621 637 click: function() {
622 638 that.selected.forEach(function(item) {
623 639 that.contents.copy(item.path, that.notebook_path).then(function () {
624 640 that.load_list();
625 641 }).catch(function(e) {
626 642 dialog.modal({
627 643 title: "Delete Failed",
628 644 body: $('<div/>')
629 645 .text("An error occurred while deleting \"" + item.path + "\".")
630 646 .append($('<div/>')
631 647 .addClass('alert alert-danger')
632 648 .text(e.message || e)),
633 649 buttons: {
634 650 OK: {'class': 'btn-primary'}
635 651 }
636 652 });
637 653 });
638 654 });
639 655 }
640 656 },
641 657 Cancel : {}
642 658 }
643 659 });
644 660 };
645 661
646 662 NotebookList.prototype.notebook_deleted = function(path) {
647 663 /**
648 664 * Remove the deleted notebook.
649 665 */
650 666 var that = this;
651 667 $( ":data(path)" ).each(function() {
652 668 var element = $(this);
653 669 if (element.data("path") === path) {
654 670 element.remove();
655 671 events.trigger('notebook_deleted.NotebookList');
656 672 that._selection_changed();
657 673 }
658 674 });
659 675 };
660 676
661 677
662 678 NotebookList.prototype.add_upload_button = function (item) {
663 679 var that = this;
664 680 var upload_button = $('<button/>').text("Upload")
665 681 .addClass('btn btn-primary btn-xs upload_button')
666 682 .click(function (e) {
667 683 var filename = item.find('.item_name > input').val();
668 684 var path = utils.url_path_join(that.notebook_path, filename);
669 685 var filedata = item.data('filedata');
670 686 var format = 'text';
671 687 if (filename.length === 0 || filename[0] === '.') {
672 688 dialog.modal({
673 689 title : 'Invalid file name',
674 690 body : "File names must be at least one character and not start with a dot",
675 691 buttons : {'OK' : { 'class' : 'btn-primary' }}
676 692 });
677 693 return false;
678 694 }
679 695 if (filedata instanceof ArrayBuffer) {
680 696 // base64-encode binary file data
681 697 var bytes = '';
682 698 var buf = new Uint8Array(filedata);
683 699 var nbytes = buf.byteLength;
684 700 for (var i=0; i<nbytes; i++) {
685 701 bytes += String.fromCharCode(buf[i]);
686 702 }
687 703 filedata = btoa(bytes);
688 704 format = 'base64';
689 705 }
690 706 var model = {};
691 707
692 708 var name_and_ext = utils.splitext(filename);
693 709 var file_ext = name_and_ext[1];
694 710 var content_type;
695 711 if (file_ext === '.ipynb') {
696 712 model.type = 'notebook';
697 713 model.format = 'json';
698 714 try {
699 715 model.content = JSON.parse(filedata);
700 716 } catch (e) {
701 717 dialog.modal({
702 718 title : 'Cannot upload invalid Notebook',
703 719 body : "The error was: " + e,
704 720 buttons : {'OK' : {
705 721 'class' : 'btn-primary',
706 722 click: function () {
707 723 item.remove();
708 724 }
709 725 }}
710 726 });
711 727 return false;
712 728 }
713 729 content_type = 'application/json';
714 730 } else {
715 731 model.type = 'file';
716 732 model.format = format;
717 733 model.content = filedata;
718 734 content_type = 'application/octet-stream';
719 735 }
720 736 filedata = item.data('filedata');
721 737
722 738 var on_success = function () {
723 739 item.removeClass('new-file');
724 740 that.add_link(model, item);
725 741 that.session_list.load_sessions();
726 742 };
727 743
728 744 var exists = false;
729 745 $.each(that.element.find('.list_item:not(.new-file)'), function(k,v){
730 746 if ($(v).data('name') === filename) { exists = true; return false; }
731 747 });
732 748
733 749 if (exists) {
734 750 dialog.modal({
735 751 title : "Replace file",
736 752 body : 'There is already a file named ' + filename + ', do you want to replace it?',
737 753 buttons : {
738 754 Overwrite : {
739 755 class: "btn-danger",
740 756 click: function () {
741 757 that.contents.save(path, model).then(on_success);
742 758 }
743 759 },
744 760 Cancel : {
745 761 click: function() { item.remove(); }
746 762 }
747 763 }
748 764 });
749 765 } else {
750 766 that.contents.save(path, model).then(on_success);
751 767 }
752 768
753 769 return false;
754 770 });
755 771 var cancel_button = $('<button/>').text("Cancel")
756 772 .addClass("btn btn-default btn-xs")
757 773 .click(function (e) {
758 774 item.remove();
759 775 return false;
760 776 });
761 777 item.find(".item_buttons").empty()
762 778 .append(upload_button)
763 779 .append(cancel_button);
764 780 };
765 781
766 782
767 783 // Backwards compatability.
768 784 IPython.NotebookList = NotebookList;
769 785
770 786 return {'NotebookList': NotebookList};
771 787 });
General Comments 0
You need to be logged in to leave comments. Login now