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