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