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