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