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