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