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