##// END OF EJS Templates
Make upload work with new UI
Jonathan Frederic -
Show More
@@ -1,722 +1,723 b''
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'jquery',
6 'jquery',
7 'base/js/utils',
7 'base/js/utils',
8 'base/js/dialog',
8 'base/js/dialog',
9 'base/js/events',
9 'base/js/events',
10 'base/js/keyboard',
10 'base/js/keyboard',
11 ], function(IPython, $, utils, dialog, events, keyboard) {
11 ], function(IPython, $, utils, dialog, events, keyboard) {
12 "use strict";
12 "use strict";
13
13
14 var NotebookList = function (selector, options) {
14 var NotebookList = function (selector, options) {
15 /**
15 /**
16 * Constructor
16 * Constructor
17 *
17 *
18 * Parameters:
18 * Parameters:
19 * selector: string
19 * selector: string
20 * options: dictionary
20 * options: dictionary
21 * Dictionary of keyword arguments.
21 * Dictionary of keyword arguments.
22 * session_list: SessionList instance
22 * session_list: SessionList instance
23 * element_name: string
23 * element_name: string
24 * base_url: string
24 * base_url: string
25 * notebook_path: string
25 * notebook_path: string
26 * contents: Contents instance
26 * contents: Contents instance
27 */
27 */
28 var that = this;
28 var that = this;
29 this.session_list = options.session_list;
29 this.session_list = options.session_list;
30 // allow code re-use by just changing element_name in kernellist.js
30 // allow code re-use by just changing element_name in kernellist.js
31 this.element_name = options.element_name || 'notebook';
31 this.element_name = options.element_name || 'notebook';
32 this.selector = selector;
32 this.selector = selector;
33 if (this.selector !== undefined) {
33 if (this.selector !== undefined) {
34 this.element = $(selector);
34 this.element = $(selector);
35 this.style();
35 this.style();
36 this.bind_events();
36 this.bind_events();
37 }
37 }
38 this.notebooks_list = [];
38 this.notebooks_list = [];
39 this.sessions = {};
39 this.sessions = {};
40 this.base_url = options.base_url || utils.get_body_data("baseUrl");
40 this.base_url = options.base_url || utils.get_body_data("baseUrl");
41 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
41 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
42 this.contents = options.contents;
42 this.contents = options.contents;
43 if (this.session_list && this.session_list.events) {
43 if (this.session_list && this.session_list.events) {
44 this.session_list.events.on('sessions_loaded.Dashboard',
44 this.session_list.events.on('sessions_loaded.Dashboard',
45 function(e, d) { that.sessions_loaded(d); });
45 function(e, d) { that.sessions_loaded(d); });
46 }
46 }
47 };
47 };
48
48
49 NotebookList.prototype.style = function () {
49 NotebookList.prototype.style = function () {
50 var prefix = '#' + this.element_name;
50 var prefix = '#' + this.element_name;
51 $(prefix + '_toolbar').addClass('list_toolbar');
51 $(prefix + '_toolbar').addClass('list_toolbar');
52 $(prefix + '_list_info').addClass('toolbar_info');
52 $(prefix + '_list_info').addClass('toolbar_info');
53 $(prefix + '_buttons').addClass('toolbar_buttons');
53 $(prefix + '_buttons').addClass('toolbar_buttons');
54 $(prefix + '_list_header').addClass('list_header');
54 $(prefix + '_list_header').addClass('list_header');
55 this.element.addClass("list_container");
55 this.element.addClass("list_container");
56 };
56 };
57
57
58 NotebookList.prototype.bind_events = function () {
58 NotebookList.prototype.bind_events = function () {
59 var that = this;
59 var that = this;
60 $('#refresh_' + this.element_name + '_list').click(function () {
60 $('#refresh_' + this.element_name + '_list').click(function () {
61 that.load_sessions();
61 that.load_sessions();
62 });
62 });
63 this.element.bind('dragover', function () {
63 this.element.bind('dragover', function () {
64 return false;
64 return false;
65 });
65 });
66 this.element.bind('drop', function(event){
66 this.element.bind('drop', function(event){
67 that.handleFilesUpload(event,'drop');
67 that.handleFilesUpload(event,'drop');
68 return false;
68 return false;
69 });
69 });
70
70
71 // Bind events for singleton controls.
71 // Bind events for singleton controls.
72 if (!NotebookList._bound_singletons) {
72 if (!NotebookList._bound_singletons) {
73 NotebookList._bound_singletons = true;
73 NotebookList._bound_singletons = true;
74 $('#new-file').click(function(e) {
74 $('#new-file').click(function(e) {
75 var w = window.open();
75 var w = window.open();
76 that.contents.new_untitled(that.notebook_path || '', {type: 'file', ext: '.txt'}).then(function(data) {
76 that.contents.new_untitled(that.notebook_path || '', {type: 'file', ext: '.txt'}).then(function(data) {
77 var url = utils.url_join_encode(
77 var url = utils.url_join_encode(
78 that.base_url, 'edit', data.path
78 that.base_url, 'edit', data.path
79 );
79 );
80 w.location = url;
80 w.location = url;
81 });
81 });
82 that.load_sessions();
82 that.load_sessions();
83 });
83 });
84 $('#new-folder').click(function(e) {
84 $('#new-folder').click(function(e) {
85 that.contents.new_untitled(that.notebook_path || '', {type: 'directory'})
85 that.contents.new_untitled(that.notebook_path || '', {type: 'directory'})
86 .then(function(){
86 .then(function(){
87 that.load_list();
87 that.load_list();
88 });
88 });
89 });
89 });
90
90
91 $('.rename-button').click($.proxy(this.rename_selected, this));
91 $('.rename-button').click($.proxy(this.rename_selected, this));
92 $('.shutdown-button').click($.proxy(this.shutdown_selected, this));
92 $('.shutdown-button').click($.proxy(this.shutdown_selected, this));
93 $('.duplicate-button').click($.proxy(this.duplicate_selected, this));
93 $('.duplicate-button').click($.proxy(this.duplicate_selected, this));
94 $('.delete-button').click($.proxy(this.delete_selected, this));
94 $('.delete-button').click($.proxy(this.delete_selected, this));
95 }
95 }
96 };
96 };
97
97
98 NotebookList.prototype.handleFilesUpload = function(event, dropOrForm) {
98 NotebookList.prototype.handleFilesUpload = function(event, dropOrForm) {
99 var that = this;
99 var that = this;
100 var files;
100 var files;
101 if(dropOrForm =='drop'){
101 if(dropOrForm =='drop'){
102 files = event.originalEvent.dataTransfer.files;
102 files = event.originalEvent.dataTransfer.files;
103 } else
103 } else
104 {
104 {
105 files = event.originalEvent.target.files;
105 files = event.originalEvent.target.files;
106 }
106 }
107 for (var i = 0; i < files.length; i++) {
107 for (var i = 0; i < files.length; i++) {
108 var f = files[i];
108 var f = files[i];
109 var name_and_ext = utils.splitext(f.name);
109 var name_and_ext = utils.splitext(f.name);
110 var file_ext = name_and_ext[1];
110 var file_ext = name_and_ext[1];
111
111
112 var reader = new FileReader();
112 var reader = new FileReader();
113 if (file_ext === '.ipynb') {
113 if (file_ext === '.ipynb') {
114 reader.readAsText(f);
114 reader.readAsText(f);
115 } else {
115 } else {
116 // read non-notebook files as binary
116 // read non-notebook files as binary
117 reader.readAsArrayBuffer(f);
117 reader.readAsArrayBuffer(f);
118 }
118 }
119 var item = that.new_item(0, true);
119 var item = that.new_item(0, true);
120 item.addClass('new-file');
120 item.addClass('new-file');
121 that.add_name_input(f.name, item, file_ext == '.ipynb' ? 'notebook' : 'file');
121 that.add_name_input(f.name, item, file_ext == '.ipynb' ? 'notebook' : 'file');
122 // Store the list item in the reader so we can use it later
122 // Store the list item in the reader so we can use it later
123 // to know which item it belongs to.
123 // to know which item it belongs to.
124 $(reader).data('item', item);
124 $(reader).data('item', item);
125 reader.onload = function (event) {
125 reader.onload = function (event) {
126 var item = $(event.target).data('item');
126 var item = $(event.target).data('item');
127 that.add_file_data(event.target.result, item);
127 that.add_file_data(event.target.result, item);
128 that.add_upload_button(item);
128 that.add_upload_button(item);
129 };
129 };
130 reader.onerror = function (event) {
130 reader.onerror = function (event) {
131 var item = $(event.target).data('item');
131 var item = $(event.target).data('item');
132 var name = item.data('name');
132 var name = item.data('name');
133 item.remove();
133 item.remove();
134 dialog.modal({
134 dialog.modal({
135 title : 'Failed to read file',
135 title : 'Failed to read file',
136 body : "Failed to read file '" + name + "'",
136 body : "Failed to read file '" + name + "'",
137 buttons : {'OK' : { 'class' : 'btn-primary' }}
137 buttons : {'OK' : { 'class' : 'btn-primary' }}
138 });
138 });
139 };
139 };
140 }
140 }
141 // Replace the file input form wth a clone of itself. This is required to
141 // Replace the file input form wth a clone of itself. This is required to
142 // reset the form. Otherwise, if you upload a file, delete it and try to
142 // reset the form. Otherwise, if you upload a file, delete it and try to
143 // upload it again, the changed event won't fire.
143 // upload it again, the changed event won't fire.
144 var form = $('input.fileinput');
144 var form = $('input.fileinput');
145 form.replaceWith(form.clone(true));
145 form.replaceWith(form.clone(true));
146 return false;
146 return false;
147 };
147 };
148
148
149 NotebookList.prototype.clear_list = function (remove_uploads) {
149 NotebookList.prototype.clear_list = function (remove_uploads) {
150 /**
150 /**
151 * Clears the navigation tree.
151 * Clears the navigation tree.
152 *
152 *
153 * Parameters
153 * Parameters
154 * remove_uploads: bool=False
154 * remove_uploads: bool=False
155 * Should upload prompts also be removed from the tree.
155 * Should upload prompts also be removed from the tree.
156 */
156 */
157 if (remove_uploads) {
157 if (remove_uploads) {
158 this.element.children('.list_item').remove();
158 this.element.children('.list_item').remove();
159 } else {
159 } else {
160 this.element.children('.list_item:not(.new-file)').remove();
160 this.element.children('.list_item:not(.new-file)').remove();
161 }
161 }
162 };
162 };
163
163
164 NotebookList.prototype.load_sessions = function(){
164 NotebookList.prototype.load_sessions = function(){
165 this.session_list.load_sessions();
165 this.session_list.load_sessions();
166 };
166 };
167
167
168
168
169 NotebookList.prototype.sessions_loaded = function(data){
169 NotebookList.prototype.sessions_loaded = function(data){
170 this.sessions = data;
170 this.sessions = data;
171 this.load_list();
171 this.load_list();
172 };
172 };
173
173
174 NotebookList.prototype.load_list = function () {
174 NotebookList.prototype.load_list = function () {
175 var that = this;
175 var that = this;
176 this.contents.list_contents(that.notebook_path).then(
176 this.contents.list_contents(that.notebook_path).then(
177 $.proxy(this.draw_notebook_list, this),
177 $.proxy(this.draw_notebook_list, this),
178 function(error) {
178 function(error) {
179 that.draw_notebook_list({content: []}, "Server error: " + error.message);
179 that.draw_notebook_list({content: []}, "Server error: " + error.message);
180 }
180 }
181 );
181 );
182 };
182 };
183
183
184 /**
184 /**
185 * Draw the list of notebooks
185 * Draw the list of notebooks
186 * @method draw_notebook_list
186 * @method draw_notebook_list
187 * @param {Array} list An array of dictionaries representing files or
187 * @param {Array} list An array of dictionaries representing files or
188 * directories.
188 * directories.
189 * @param {String} error_msg An error message
189 * @param {String} error_msg An error message
190 */
190 */
191
191
192
192
193 var type_order = {'directory':0,'notebook':1,'file':2};
193 var type_order = {'directory':0,'notebook':1,'file':2};
194
194
195 NotebookList.prototype.draw_notebook_list = function (list, error_msg) {
195 NotebookList.prototype.draw_notebook_list = function (list, error_msg) {
196 list.content.sort(function(a, b) {
196 list.content.sort(function(a, b) {
197 if (type_order[a['type']] < type_order[b['type']]) {
197 if (type_order[a['type']] < type_order[b['type']]) {
198 return -1;
198 return -1;
199 }
199 }
200 if (type_order[a['type']] > type_order[b['type']]) {
200 if (type_order[a['type']] > type_order[b['type']]) {
201 return 1;
201 return 1;
202 }
202 }
203 if (a['name'] < b['name']) {
203 if (a['name'] < b['name']) {
204 return -1;
204 return -1;
205 }
205 }
206 if (a['name'] > b['name']) {
206 if (a['name'] > b['name']) {
207 return 1;
207 return 1;
208 }
208 }
209 return 0;
209 return 0;
210 });
210 });
211 var message = error_msg || 'Notebook list empty.';
211 var message = error_msg || 'Notebook list empty.';
212 var item = null;
212 var item = null;
213 var model = null;
213 var model = null;
214 var len = list.content.length;
214 var len = list.content.length;
215 this.clear_list();
215 this.clear_list();
216 var n_uploads = this.element.children('.list_item').length;
216 var n_uploads = this.element.children('.list_item').length;
217 if (len === 0) {
217 if (len === 0) {
218 item = this.new_item(0);
218 item = this.new_item(0);
219 var span12 = item.children().first();
219 var span12 = item.children().first();
220 span12.empty();
220 span12.empty();
221 span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
221 span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
222 }
222 }
223 var path = this.notebook_path;
223 var path = this.notebook_path;
224 var offset = n_uploads;
224 var offset = n_uploads;
225 if (path !== '') {
225 if (path !== '') {
226 item = this.new_item(offset, false);
226 item = this.new_item(offset, false);
227 model = {
227 model = {
228 type: 'directory',
228 type: 'directory',
229 name: '..',
229 name: '..',
230 path: utils.url_path_split(path)[0],
230 path: utils.url_path_split(path)[0],
231 };
231 };
232 this.add_link(model, item);
232 this.add_link(model, item);
233 offset += 1;
233 offset += 1;
234 }
234 }
235 for (var i=0; i<len; i++) {
235 for (var i=0; i<len; i++) {
236 model = list.content[i];
236 model = list.content[i];
237 item = this.new_item(i+offset, true);
237 item = this.new_item(i+offset, true);
238 this.add_link(model, item);
238 this.add_link(model, item);
239 }
239 }
240 // Trigger an event when we've finished drawing the notebook list.
240 // Trigger an event when we've finished drawing the notebook list.
241 events.trigger('draw_notebook_list.NotebookList');
241 events.trigger('draw_notebook_list.NotebookList');
242 this._selection_changed();
242 this._selection_changed();
243 };
243 };
244
244
245
245
246 /**
246 /**
247 * Creates a new item.
247 * Creates a new item.
248 * @param {integer} index
248 * @param {integer} index
249 * @param {boolean} [selectable] - tristate, undefined: don't draw checkbox,
249 * @param {boolean} [selectable] - tristate, undefined: don't draw checkbox,
250 * false: don't draw checkbox but pad
250 * false: don't draw checkbox but pad
251 * where it should be, true: draw checkbox.
251 * where it should be, true: draw checkbox.
252 * @return {JQuery} row
252 * @return {JQuery} row
253 */
253 */
254 NotebookList.prototype.new_item = function (index, selectable) {
254 NotebookList.prototype.new_item = function (index, selectable) {
255 var row = $('<div/>')
255 var row = $('<div/>')
256 .addClass("list_item")
256 .addClass("list_item")
257 .addClass("row");
257 .addClass("row");
258
258
259 var item = $("<div/>")
259 var item = $("<div/>")
260 .addClass("col-md-12")
260 .addClass("col-md-12")
261 .appendTo(row);
261 .appendTo(row);
262
262
263 var checkbox;
263 var checkbox;
264 if (selectable !== undefined) {
264 if (selectable !== undefined) {
265 checkbox = $('<input/>')
265 checkbox = $('<input/>')
266 .attr('type', 'checkbox')
266 .attr('type', 'checkbox')
267 .attr('title', 'Click here to rename, delete, etc.')
267 .attr('title', 'Click here to rename, delete, etc.')
268 .appendTo(item);
268 .appendTo(item);
269 }
269 }
270
270
271 $('<i/>')
271 $('<i/>')
272 .addClass('item_icon')
272 .addClass('item_icon')
273 .appendTo(item);
273 .appendTo(item);
274
274
275 var link = $("<a/>")
275 var link = $("<a/>")
276 .addClass("item_link")
276 .addClass("item_link")
277 .appendTo(item);
277 .appendTo(item);
278
278
279 $("<span/>")
279 $("<span/>")
280 .addClass("item_name")
280 .addClass("item_name")
281 .appendTo(link);
281 .appendTo(link);
282
282
283 if (selectable === false) {
283 if (selectable === false) {
284 checkbox.css('visibility', 'hidden');
284 checkbox.css('visibility', 'hidden');
285 } else if (selectable === true) {
285 } else if (selectable === true) {
286 var that = this;
286 var that = this;
287 link.click(function(e) {
287 link.click(function(e) {
288 e.stopPropagation();
288 e.stopPropagation();
289 });
289 });
290 checkbox.click(function(e) {
290 checkbox.click(function(e) {
291 e.stopPropagation();
291 e.stopPropagation();
292 that._selection_changed();
292 that._selection_changed();
293 });
293 });
294 row.click(function(e) {
294 row.click(function(e) {
295 e.stopPropagation();
295 e.stopPropagation();
296 checkbox.prop('checked', !checkbox.prop('checked'));
296 checkbox.prop('checked', !checkbox.prop('checked'));
297 that._selection_changed();
297 that._selection_changed();
298 });
298 });
299 }
299 }
300
300
301 var buttons = $('<div/>')
301 var buttons = $('<div/>')
302 .addClass("item_buttons pull-right")
302 .addClass("item_buttons pull-right")
303 .appendTo(item);
303 .appendTo(item);
304
304
305 $('<div/>')
305 $('<div/>')
306 .addClass('running-indicator')
306 .addClass('running-indicator')
307 .text('Running')
307 .text('Running')
308 .css('visibility', 'hidden')
308 .css('visibility', 'hidden')
309 .appendTo(buttons);
309 .appendTo(buttons);
310
310
311 if (index === -1) {
311 if (index === -1) {
312 this.element.append(row);
312 this.element.append(row);
313 } else {
313 } else {
314 this.element.children().eq(index).after(row);
314 this.element.children().eq(index).after(row);
315 }
315 }
316 return row;
316 return row;
317 };
317 };
318
318
319
319
320 NotebookList.icons = {
320 NotebookList.icons = {
321 directory: 'folder_icon',
321 directory: 'folder_icon',
322 notebook: 'notebook_icon',
322 notebook: 'notebook_icon',
323 file: 'file_icon',
323 file: 'file_icon',
324 };
324 };
325
325
326 NotebookList.uri_prefixes = {
326 NotebookList.uri_prefixes = {
327 directory: 'tree',
327 directory: 'tree',
328 notebook: 'notebooks',
328 notebook: 'notebooks',
329 file: 'edit',
329 file: 'edit',
330 };
330 };
331
331
332 NotebookList.prototype._selection_changed = function() {
332 NotebookList.prototype._selection_changed = function() {
333 var selected = [];
333 var selected = [];
334 var has_running_notebook = false;
334 var has_running_notebook = false;
335 var has_directory = false;
335 var has_directory = false;
336 var has_file = false;
336 var has_file = false;
337 var that = this;
337 var that = this;
338 $('.list_item :checked').each(function(index, item) {
338 $('.list_item :checked').each(function(index, item) {
339 var parent = $(item).parent().parent();
339 var parent = $(item).parent().parent();
340 selected.push({
340 if (parent.find('.upload_button').length === 0) {
341 name: parent.data('name'),
341 selected.push({
342 path: parent.data('path'),
342 name: parent.data('name'),
343 type: parent.data('type')
343 path: parent.data('path'),
344 });
344 type: parent.data('type')
345 });
345
346
346 has_running_notebook = has_running_notebook ||
347 has_running_notebook = has_running_notebook ||
347 (parent.data('type') == 'notebook' && that.sessions[parent.data('path')] !== undefined);
348 (parent.data('type') == 'notebook' && that.sessions[parent.data('path')] !== undefined);
348 has_file = has_file || parent.data('type') == 'file';
349 has_file = has_file || parent.data('type') == 'file';
349 has_directory = has_directory || parent.data('type') == 'directory';
350 has_directory = has_directory || parent.data('type') == 'directory';
351 }
350 });
352 });
351 this.selected = selected;
353 this.selected = selected;
352
354
353 // Rename is only visible when one item is selected.
355 // Rename is only visible when one item is selected.
354 if (selected.length==1) {
356 if (selected.length==1) {
355 $('.rename-button').css('display', 'inline-block');
357 $('.rename-button').css('display', 'inline-block');
356 } else {
358 } else {
357 $('.rename-button').css('display', 'none');
359 $('.rename-button').css('display', 'none');
358 }
360 }
359
361
360 // Shutdown is only visible when one or more notebooks are visible.
362 // Shutdown is only visible when one or more notebooks are visible.
361 if (has_running_notebook && !(has_file || has_directory)) {
363 if (has_running_notebook && !(has_file || has_directory)) {
362 $('.shutdown-button').css('display', 'inline-block');
364 $('.shutdown-button').css('display', 'inline-block');
363 } else {
365 } else {
364 $('.shutdown-button').css('display', 'none');
366 $('.shutdown-button').css('display', 'none');
365 }
367 }
366
368
367 // Duplicate isn't visible if a directory is selected.
369 // Duplicate isn't visible if a directory is selected.
368 if (selected.length > 0 && !has_directory) {
370 if (selected.length > 0 && !has_directory) {
369 $('.duplicate-button').css('display', 'inline-block');
371 $('.duplicate-button').css('display', 'inline-block');
370 } else {
372 } else {
371 $('.duplicate-button').css('display', 'none');
373 $('.duplicate-button').css('display', 'none');
372 }
374 }
373
375
374 // Delete is visible if one or more items are selected.
376 // Delete is visible if one or more items are selected.
375 if (selected.length > 0) {
377 if (selected.length > 0) {
376 $('.delete-button').css('display', 'inline-block');
378 $('.delete-button').css('display', 'inline-block');
377 } else {
379 } else {
378 $('.delete-button').css('display', 'none');
380 $('.delete-button').css('display', 'none');
379 }
381 }
380 };
382 };
381
383
382 NotebookList.prototype.add_link = function (model, item) {
384 NotebookList.prototype.add_link = function (model, item) {
383 var path = model.path,
385 var path = model.path,
384 name = model.name;
386 name = model.name;
385 item.data('name', name);
387 item.data('name', name);
386 item.data('path', path);
388 item.data('path', path);
387 item.data('type', model.type);
389 item.data('type', model.type);
388 item.find(".item_name").text(name);
390 item.find(".item_name").text(name);
389 var icon = NotebookList.icons[model.type];
391 var icon = NotebookList.icons[model.type];
390 var uri_prefix = NotebookList.uri_prefixes[model.type];
392 var uri_prefix = NotebookList.uri_prefixes[model.type];
391 item.find(".item_icon").addClass(icon).addClass('icon-fixed-width');
393 item.find(".item_icon").addClass(icon).addClass('icon-fixed-width');
392 var link = item.find("a.item_link")
394 var link = item.find("a.item_link")
393 .attr('href',
395 .attr('href',
394 utils.url_join_encode(
396 utils.url_join_encode(
395 this.base_url,
397 this.base_url,
396 uri_prefix,
398 uri_prefix,
397 path
399 path
398 )
400 )
399 );
401 );
400
402
401 var running = (model.type == 'notebook' && this.sessions[path] !== undefined);
403 var running = (model.type == 'notebook' && this.sessions[path] !== undefined);
402 item.find(".item_buttons .running-indicator").css('visibility', running ? '' : 'hidden');
404 item.find(".item_buttons .running-indicator").css('visibility', running ? '' : 'hidden');
403
405
404 // directory nav doesn't open new tabs
406 // directory nav doesn't open new tabs
405 // files, notebooks do
407 // files, notebooks do
406 if (model.type !== "directory") {
408 if (model.type !== "directory") {
407 link.attr('target','_blank');
409 link.attr('target','_blank');
408 }
410 }
409 };
411 };
410
412
411
413
412 NotebookList.prototype.add_name_input = function (name, item, icon_type) {
414 NotebookList.prototype.add_name_input = function (name, item, icon_type) {
413 item.data('name', name);
415 item.data('name', name);
414 item.find(".item_icon").addClass(NotebookList.icons[icon_type]).addClass('icon-fixed-width');
416 item.find(".item_icon").addClass(NotebookList.icons[icon_type]).addClass('icon-fixed-width');
415 item.find(".item_name").empty().append(
417 item.find(".item_name").empty().append(
416 $('<input/>')
418 $('<input/>')
417 .addClass("filename_input")
419 .addClass("filename_input")
418 .attr('value', name)
420 .attr('value', name)
419 .attr('size', '30')
421 .attr('size', '30')
420 .attr('type', 'text')
422 .attr('type', 'text')
421 .keyup(function(event){
423 .keyup(function(event){
422 if(event.keyCode == 13){item.find('.upload_button').click();}
424 if(event.keyCode == 13){item.find('.upload_button').click();}
423 else if(event.keyCode == 27){item.remove();}
425 else if(event.keyCode == 27){item.remove();}
424 })
426 })
425 );
427 );
426 };
428 };
427
429
428
430
429 NotebookList.prototype.add_file_data = function (data, item) {
431 NotebookList.prototype.add_file_data = function (data, item) {
430 item.data('filedata', data);
432 item.data('filedata', data);
431 };
433 };
432
434
433
435
434 NotebookList.prototype.shutdown_selected = function() {
436 NotebookList.prototype.shutdown_selected = function() {
435 var that = this;
437 var that = this;
436 this.selected.forEach(function(item) {
438 this.selected.forEach(function(item) {
437 if (item.type == 'notebook') {
439 if (item.type == 'notebook') {
438 that.shutdown_notebook(item.path);
440 that.shutdown_notebook(item.path);
439 }
441 }
440 });
442 });
441 };
443 };
442
444
443 NotebookList.prototype.shutdown_notebook = function(path) {
445 NotebookList.prototype.shutdown_notebook = function(path) {
444 var that = this;
446 var that = this;
445 var settings = {
447 var settings = {
446 processData : false,
448 processData : false,
447 cache : false,
449 cache : false,
448 type : "DELETE",
450 type : "DELETE",
449 dataType : "json",
451 dataType : "json",
450 success : function () {
452 success : function () {
451 that.load_sessions();
453 that.load_sessions();
452 },
454 },
453 error : utils.log_ajax_error,
455 error : utils.log_ajax_error,
454 };
456 };
455
457
456 var session = this.sessions[path];
458 var session = this.sessions[path];
457 if (session) {
459 if (session) {
458 var url = utils.url_join_encode(
460 var url = utils.url_join_encode(
459 this.base_url,
461 this.base_url,
460 'api/sessions',
462 'api/sessions',
461 session
463 session
462 );
464 );
463 $.ajax(url, settings);
465 $.ajax(url, settings);
464 }
466 }
465 }
467 }
466
468
467 NotebookList.prototype.rename_selected = function() {
469 NotebookList.prototype.rename_selected = function() {
468 if (this.selected.length != 1) return;
470 if (this.selected.length != 1) return;
469
471
470 var that = this;
472 var that = this;
471 var path = this.selected[0].path;
473 var path = this.selected[0].path;
472 var input = $('<input/>').attr('type','text').attr('size','25').addClass('form-control')
474 var input = $('<input/>').attr('type','text').attr('size','25').addClass('form-control')
473 .val(path);
475 .val(path);
474 var dialog_body = $('<div/>').append(
476 var dialog_body = $('<div/>').append(
475 $("<p/>").addClass("rename-message")
477 $("<p/>").addClass("rename-message")
476 .text('Enter a new directory name:')
478 .text('Enter a new directory name:')
477 ).append(
479 ).append(
478 $("<br/>")
480 $("<br/>")
479 ).append(input);
481 ).append(input);
480 var d = dialog.modal({
482 var d = dialog.modal({
481 title : "Rename directory",
483 title : "Rename directory",
482 body : dialog_body,
484 body : dialog_body,
483 buttons : {
485 buttons : {
484 OK : {
486 OK : {
485 class: "btn-primary",
487 class: "btn-primary",
486 click: function() {
488 click: function() {
487 that.contents.rename(path, input.val()).then(function() {
489 that.contents.rename(path, input.val()).then(function() {
488 that.load_list();
490 that.load_list();
489 }).catch(function(e) {
491 }).catch(function(e) {
490 dialog.modal({
492 dialog.modal({
491 title : "Error",
493 title : "Error",
492 body : $('<div/>')
494 body : $('<div/>')
493 .text("An error occurred while renaming \"" + path + "\" to \"" + input.val() + "\".")
495 .text("An error occurred while renaming \"" + path + "\" to \"" + input.val() + "\".")
494 .append($('<div/>').addClass('alert alert-danger').text(String(e))),
496 .append($('<div/>').addClass('alert alert-danger').text(String(e))),
495 buttons : {
497 buttons : {
496 OK : {}
498 OK : {}
497 }
499 }
498 });
500 });
499 });
501 });
500 }
502 }
501 },
503 },
502 Cancel : {}
504 Cancel : {}
503 },
505 },
504 open : function () {
506 open : function () {
505 // Upon ENTER, click the OK button.
507 // Upon ENTER, click the OK button.
506 input.keydown(function (event) {
508 input.keydown(function (event) {
507 if (event.which === keyboard.keycodes.enter) {
509 if (event.which === keyboard.keycodes.enter) {
508 d.find('.btn-primary').first().click();
510 d.find('.btn-primary').first().click();
509 return false;
511 return false;
510 }
512 }
511 });
513 });
512 input.focus().select();
514 input.focus().select();
513 }
515 }
514 });
516 });
515 };
517 };
516
518
517 NotebookList.prototype.delete_selected = function() {
519 NotebookList.prototype.delete_selected = function() {
518 var message;
520 var message;
519 if (this.selected.length == 1) {
521 if (this.selected.length == 1) {
520 message = 'Are you sure you want to permanently delete: ' + this.selected[0].name + '?';
522 message = 'Are you sure you want to permanently delete: ' + this.selected[0].name + '?';
521 } else {
523 } else {
522 message = 'Are you sure you want to permanently delete the ' + this.selected.length + ' files/folders selected?';
524 message = 'Are you sure you want to permanently delete the ' + this.selected.length + ' files/folders selected?';
523 }
525 }
524 var that = this;
526 var that = this;
525 dialog.modal({
527 dialog.modal({
526 title : "Delete",
528 title : "Delete",
527 body : message,
529 body : message,
528 buttons : {
530 buttons : {
529 Delete : {
531 Delete : {
530 class: "btn-danger",
532 class: "btn-danger",
531 click: function() {
533 click: function() {
532 // Shutdown any/all selected notebooks before deleting
534 // Shutdown any/all selected notebooks before deleting
533 // the files.
535 // the files.
534 that.shutdown_selected();
536 that.shutdown_selected();
535
537
536 // Delete selected.
538 // Delete selected.
537 that.selected.forEach(function(item) {
539 that.selected.forEach(function(item) {
538 that.contents.delete(item.path).then(function() {
540 that.contents.delete(item.path).then(function() {
539 that.notebook_deleted(item.path);
541 that.notebook_deleted(item.path);
540 }).catch(function(e) {
542 }).catch(function(e) {
541 dialog.modal({
543 dialog.modal({
542 title : "Error",
544 title : "Error",
543 body : $('<div/>')
545 body : $('<div/>')
544 .text("An error occurred while deleting \"" + item.path + "\".")
546 .text("An error occurred while deleting \"" + item.path + "\".")
545 .append($('<div/>').addClass('alert alert-danger').text(String(e))),
547 .append($('<div/>').addClass('alert alert-danger').text(String(e))),
546 buttons : {
548 buttons : {
547 OK : {}
549 OK : {}
548 }
550 }
549 });
551 });
550 });
552 });
551 });
553 });
552 }
554 }
553 },
555 },
554 Cancel : {}
556 Cancel : {}
555 }
557 }
556 });
558 });
557 };
559 };
558
560
559 NotebookList.prototype.duplicate_selected = function() {
561 NotebookList.prototype.duplicate_selected = function() {
560 var message;
562 var message;
561 if (this.selected.length == 1) {
563 if (this.selected.length == 1) {
562 message = 'Are you sure you want to duplicate: ' + this.selected[0].name + '?';
564 message = 'Are you sure you want to duplicate: ' + this.selected[0].name + '?';
563 } else {
565 } else {
564 message = 'Are you sure you want to duplicate the ' + this.selected.length + ' files selected?';
566 message = 'Are you sure you want to duplicate the ' + this.selected.length + ' files selected?';
565 }
567 }
566 var that = this;
568 var that = this;
567 dialog.modal({
569 dialog.modal({
568 title : "Delete",
570 title : "Delete",
569 body : message,
571 body : message,
570 buttons : {
572 buttons : {
571 Duplicate : {
573 Duplicate : {
572 class: "btn-primary",
574 class: "btn-primary",
573 click: function() {
575 click: function() {
574 that.selected.forEach(function(item) {
576 that.selected.forEach(function(item) {
575 that.contents.copy(item.path, that.notebook_path).then(function () {
577 that.contents.copy(item.path, that.notebook_path).then(function () {
576 that.load_list();
578 that.load_list();
577 }).catch(function(e) {
579 }).catch(function(e) {
578 dialog.modal({
580 dialog.modal({
579 title : "Error",
581 title : "Error",
580 body : $('<div/>')
582 body : $('<div/>')
581 .text("An error occurred while copying \"" + item.path + "\".")
583 .text("An error occurred while copying \"" + item.path + "\".")
582 .append($('<div/>').addClass('alert alert-danger').text(String(e))),
584 .append($('<div/>').addClass('alert alert-danger').text(String(e))),
583 buttons : {
585 buttons : {
584 OK : {}
586 OK : {}
585 }
587 }
586 });
588 });
587 });
589 });
588 });
590 });
589 }
591 }
590 },
592 },
591 Cancel : {}
593 Cancel : {}
592 }
594 }
593 });
595 });
594 };
596 };
595
597
596 NotebookList.prototype.notebook_deleted = function(path) {
598 NotebookList.prototype.notebook_deleted = function(path) {
597 /**
599 /**
598 * Remove the deleted notebook.
600 * Remove the deleted notebook.
599 */
601 */
600 var that = this;
602 var that = this;
601 $( ":data(path)" ).each(function() {
603 $( ":data(path)" ).each(function() {
602 var element = $(this);
604 var element = $(this);
603 if (element.data("path") === path) {
605 if (element.data("path") === path) {
604 element.remove();
606 element.remove();
605 events.trigger('notebook_deleted.NotebookList');
607 events.trigger('notebook_deleted.NotebookList');
606 that._selection_changed();
608 that._selection_changed();
607 }
609 }
608 });
610 });
609 };
611 };
610
612
611
613
612 NotebookList.prototype.add_upload_button = function (item) {
614 NotebookList.prototype.add_upload_button = function (item) {
613 var that = this;
615 var that = this;
614 var upload_button = $('<button/>').text("Upload")
616 var upload_button = $('<button/>').text("Upload")
615 .addClass('btn btn-primary btn-xs upload_button')
617 .addClass('btn btn-primary btn-xs upload_button')
616 .click(function (e) {
618 .click(function (e) {
617 var filename = item.find('.item_name > input').val();
619 var filename = item.find('.item_name > input').val();
618 var path = utils.url_path_join(that.notebook_path, filename);
620 var path = utils.url_path_join(that.notebook_path, filename);
619 var filedata = item.data('filedata');
621 var filedata = item.data('filedata');
620 var format = 'text';
622 var format = 'text';
621 if (filename.length === 0 || filename[0] === '.') {
623 if (filename.length === 0 || filename[0] === '.') {
622 dialog.modal({
624 dialog.modal({
623 title : 'Invalid file name',
625 title : 'Invalid file name',
624 body : "File names must be at least one character and not start with a dot",
626 body : "File names must be at least one character and not start with a dot",
625 buttons : {'OK' : { 'class' : 'btn-primary' }}
627 buttons : {'OK' : { 'class' : 'btn-primary' }}
626 });
628 });
627 return false;
629 return false;
628 }
630 }
629 if (filedata instanceof ArrayBuffer) {
631 if (filedata instanceof ArrayBuffer) {
630 // base64-encode binary file data
632 // base64-encode binary file data
631 var bytes = '';
633 var bytes = '';
632 var buf = new Uint8Array(filedata);
634 var buf = new Uint8Array(filedata);
633 var nbytes = buf.byteLength;
635 var nbytes = buf.byteLength;
634 for (var i=0; i<nbytes; i++) {
636 for (var i=0; i<nbytes; i++) {
635 bytes += String.fromCharCode(buf[i]);
637 bytes += String.fromCharCode(buf[i]);
636 }
638 }
637 filedata = btoa(bytes);
639 filedata = btoa(bytes);
638 format = 'base64';
640 format = 'base64';
639 }
641 }
640 var model = {};
642 var model = {};
641
643
642 var name_and_ext = utils.splitext(filename);
644 var name_and_ext = utils.splitext(filename);
643 var file_ext = name_and_ext[1];
645 var file_ext = name_and_ext[1];
644 var content_type;
646 var content_type;
645 if (file_ext === '.ipynb') {
647 if (file_ext === '.ipynb') {
646 model.type = 'notebook';
648 model.type = 'notebook';
647 model.format = 'json';
649 model.format = 'json';
648 try {
650 try {
649 model.content = JSON.parse(filedata);
651 model.content = JSON.parse(filedata);
650 } catch (e) {
652 } catch (e) {
651 dialog.modal({
653 dialog.modal({
652 title : 'Cannot upload invalid Notebook',
654 title : 'Cannot upload invalid Notebook',
653 body : "The error was: " + e,
655 body : "The error was: " + e,
654 buttons : {'OK' : {
656 buttons : {'OK' : {
655 'class' : 'btn-primary',
657 'class' : 'btn-primary',
656 click: function () {
658 click: function () {
657 item.remove();
659 item.remove();
658 }
660 }
659 }}
661 }}
660 });
662 });
661 return false;
663 return false;
662 }
664 }
663 content_type = 'application/json';
665 content_type = 'application/json';
664 } else {
666 } else {
665 model.type = 'file';
667 model.type = 'file';
666 model.format = format;
668 model.format = format;
667 model.content = filedata;
669 model.content = filedata;
668 content_type = 'application/octet-stream';
670 content_type = 'application/octet-stream';
669 }
671 }
670 filedata = item.data('filedata');
672 filedata = item.data('filedata');
671
673
672 var on_success = function () {
674 var on_success = function () {
673 item.removeClass('new-file');
675 item.removeClass('new-file');
674 that.add_link(model, item);
676 that.add_link(model, item);
675 that.add_delete_button(item);
676 that.session_list.load_sessions();
677 that.session_list.load_sessions();
677 };
678 };
678
679
679 var exists = false;
680 var exists = false;
680 $.each(that.element.find('.list_item:not(.new-file)'), function(k,v){
681 $.each(that.element.find('.list_item:not(.new-file)'), function(k,v){
681 if ($(v).data('name') === filename) { exists = true; return false; }
682 if ($(v).data('name') === filename) { exists = true; return false; }
682 });
683 });
683
684
684 if (exists) {
685 if (exists) {
685 dialog.modal({
686 dialog.modal({
686 title : "Replace file",
687 title : "Replace file",
687 body : 'There is already a file named ' + filename + ', do you want to replace it?',
688 body : 'There is already a file named ' + filename + ', do you want to replace it?',
688 buttons : {
689 buttons : {
689 Overwrite : {
690 Overwrite : {
690 class: "btn-danger",
691 class: "btn-danger",
691 click: function () {
692 click: function () {
692 that.contents.save(path, model).then(on_success);
693 that.contents.save(path, model).then(on_success);
693 }
694 }
694 },
695 },
695 Cancel : {
696 Cancel : {
696 click: function() { item.remove(); }
697 click: function() { item.remove(); }
697 }
698 }
698 }
699 }
699 });
700 });
700 } else {
701 } else {
701 that.contents.save(path, model).then(on_success);
702 that.contents.save(path, model).then(on_success);
702 }
703 }
703
704
704 return false;
705 return false;
705 });
706 });
706 var cancel_button = $('<button/>').text("Cancel")
707 var cancel_button = $('<button/>').text("Cancel")
707 .addClass("btn btn-default btn-xs")
708 .addClass("btn btn-default btn-xs")
708 .click(function (e) {
709 .click(function (e) {
709 item.remove();
710 item.remove();
710 return false;
711 return false;
711 });
712 });
712 item.find(".item_buttons").empty()
713 item.find(".item_buttons").empty()
713 .append(upload_button)
714 .append(upload_button)
714 .append(cancel_button);
715 .append(cancel_button);
715 };
716 };
716
717
717
718
718 // Backwards compatability.
719 // Backwards compatability.
719 IPython.NotebookList = NotebookList;
720 IPython.NotebookList = NotebookList;
720
721
721 return {'NotebookList': NotebookList};
722 return {'NotebookList': NotebookList};
722 });
723 });
@@ -1,255 +1,259 b''
1
1
2 /**
2 /**
3 * Primary styles
3 * Primary styles
4 *
4 *
5 * Author: IPython Development Team
5 * Author: IPython Development Team
6 */
6 */
7
7
8 @dashboard_tb_pad: 4px;
8 @dashboard_tb_pad: 4px;
9 @dashboard_lr_pad: 7px;
9 @dashboard_lr_pad: 7px;
10 // These are the total heights of the Bootstrap small and mini buttons. These values
10 // These are the total heights of the Bootstrap small and mini buttons. These values
11 // are not less variables so we have to track them statically.
11 // are not less variables so we have to track them statically.
12 @btn_small_height: 24px;
12 @btn_small_height: 24px;
13 @btn_mini_height: 22px;
13 @btn_mini_height: 22px;
14 @dark_dashboard_color: @breadcrumb-color;
14 @dark_dashboard_color: @breadcrumb-color;
15
15
16 ul#tabs {
16 ul#tabs {
17 margin-bottom: @dashboard_tb_pad;
17 margin-bottom: @dashboard_tb_pad;
18 }
18 }
19
19
20 ul#tabs a {
20 ul#tabs a {
21 padding-top: @dashboard_tb_pad + 2px;
21 padding-top: @dashboard_tb_pad + 2px;
22 padding-bottom: @dashboard_tb_pad;
22 padding-bottom: @dashboard_tb_pad;
23 }
23 }
24
24
25 ul.breadcrumb {
25 ul.breadcrumb {
26 a:focus, a:hover {
26 a:focus, a:hover {
27 text-decoration: none;
27 text-decoration: none;
28 }
28 }
29 i.icon-home {
29 i.icon-home {
30 font-size: 16px;
30 font-size: 16px;
31 margin-right: 4px;
31 margin-right: 4px;
32 }
32 }
33
33
34 span {
34 span {
35 color: @dark_dashboard_color;
35 color: @dark_dashboard_color;
36 }
36 }
37 }
37 }
38
38
39 .list_toolbar {
39 .list_toolbar {
40 padding: @dashboard_tb_pad 0 @dashboard_tb_pad 0;
40 padding: @dashboard_tb_pad 0 @dashboard_tb_pad 0;
41 vertical-align: middle;
41 vertical-align: middle;
42
42
43 .tree-buttons {
43 .tree-buttons {
44 padding-top: 1px;
44 padding-top: 1px;
45 }
45 }
46 }
46 }
47
47
48 .dynamic-buttons {
48 .dynamic-buttons {
49 display: inline-block;
49 display: inline-block;
50 }
50 }
51
51
52 .list_toolbar [class*="span"] {
52 .list_toolbar [class*="span"] {
53 min-height: @btn_small_height;
53 min-height: @btn_small_height;
54 }
54 }
55
55
56 .list_header {
56 .list_header {
57 font-weight: bold;
57 font-weight: bold;
58 }
58 }
59
59
60 .list_container {
60 .list_container {
61 margin-top: @dashboard_tb_pad;
61 margin-top: @dashboard_tb_pad;
62 margin-bottom: 5*@dashboard_tb_pad;
62 margin-bottom: 5*@dashboard_tb_pad;
63 border: 1px solid @table-border-color;
63 border: 1px solid @table-border-color;
64 border-radius: @border-radius-base;
64 border-radius: @border-radius-base;
65 }
65 }
66
66
67 .list_container > div {
67 .list_container > div {
68 border-bottom: 1px solid @table-border-color;
68 border-bottom: 1px solid @table-border-color;
69 &:hover .list-item{
69 &:hover .list-item{
70 background-color: red;
70 background-color: red;
71 };
71 };
72 }
72 }
73
73
74 .list_container > div:last-child {
74 .list_container > div:last-child {
75 border: none;
75 border: none;
76 }
76 }
77
77
78 .list_item {
78 .list_item {
79 &:hover .list_item {
79 &:hover .list_item {
80 background-color: @table-border-color;
80 background-color: @table-border-color;
81 };
81 };
82 a {text-decoration: none;}
82 a {text-decoration: none;}
83 }
83 }
84
84
85 .action_col {
85 .action_col {
86 text-align: right;
86 text-align: right;
87 }
87 }
88
88
89 .list_header>div, .list_item>div {
89 .list_header>div, .list_item>div {
90 padding-top: @dashboard_tb_pad;
90 padding-top: @dashboard_tb_pad;
91 padding-bottom: @dashboard_tb_pad;
91 padding-bottom: @dashboard_tb_pad;
92 padding-left: @dashboard_lr_pad;
92 padding-left: @dashboard_lr_pad;
93 padding-right: @dashboard_lr_pad;
93 padding-right: @dashboard_lr_pad;
94 line-height: @btn_mini_height;
94 line-height: @btn_mini_height;
95
95
96 input {
96 input {
97 margin-right: @dashboard_lr_pad;
97 margin-right: @dashboard_lr_pad;
98 }
98 }
99 }
99 }
100
100
101 .new-file input[type=checkbox] {
102 visibility: hidden;
103 }
104
101 .item_name {
105 .item_name {
102 line-height: @btn_mini_height;
106 line-height: @btn_mini_height;
103 height: @btn_small_height;
107 height: @btn_small_height;
104 }
108 }
105
109
106 .item_icon {
110 .item_icon {
107 font-size: 14px;
111 font-size: 14px;
108 color: @dark_dashboard_color;
112 color: @dark_dashboard_color;
109 margin-right: @dashboard_lr_pad;
113 margin-right: @dashboard_lr_pad;
110 }
114 }
111
115
112 .item_buttons {
116 .item_buttons {
113 padding-top: @dashboard_tb_pad;
117 padding-top: @dashboard_tb_pad;
114 line-height: 1em;
118 line-height: 1em;
115 .btn-toolbar();
119 .btn-toolbar();
116 .btn {
120 .btn {
117 min-width: 13ex;
121 min-width: 13ex;
118 }
122 }
119 .running-indicator {
123 .running-indicator {
120 color: @brand-success;
124 color: @brand-success;
121 }
125 }
122 }
126 }
123
127
124 .toolbar_info {
128 .toolbar_info {
125 height: @btn_small_height;
129 height: @btn_small_height;
126 line-height: @btn_small_height;
130 line-height: @btn_small_height;
127 }
131 }
128
132
129 input.nbname_input, input.engine_num_input {
133 input.nbname_input, input.engine_num_input {
130 // These settings give these inputs a height that matches @btn_mini_height = 22
134 // These settings give these inputs a height that matches @btn_mini_height = 22
131 padding-top: 3px;
135 padding-top: 3px;
132 padding-bottom: 3px;
136 padding-bottom: 3px;
133 height: @btn_mini_height;
137 height: @btn_mini_height;
134 line-height: 14px;
138 line-height: 14px;
135 margin: 0px;
139 margin: 0px;
136 }
140 }
137
141
138 input.engine_num_input {
142 input.engine_num_input {
139 width: 60px;
143 width: 60px;
140 }
144 }
141
145
142 .highlight_text {
146 .highlight_text {
143 color: blue;
147 color: blue;
144 }
148 }
145
149
146 #project_name > .breadcrumb {
150 #project_name > .breadcrumb {
147 padding: 0px;
151 padding: 0px;
148 margin-bottom: 0px;
152 margin-bottom: 0px;
149 background-color: transparent;
153 background-color: transparent;
150 font-weight: bold;
154 font-weight: bold;
151
155
152 }
156 }
153
157
154 .tab-content .row {
158 .tab-content .row {
155 margin-left: 0px;
159 margin-left: 0px;
156 margin-right: 0px;
160 margin-right: 0px;
157 }
161 }
158
162
159 .folder_icon:before {
163 .folder_icon:before {
160 .icon(@fa-var-folder-o)
164 .icon(@fa-var-folder-o)
161 }
165 }
162
166
163 .notebook_icon:before {
167 .notebook_icon:before {
164 .icon(@fa-var-book)
168 .icon(@fa-var-book)
165 }
169 }
166
170
167 .file_icon:before {
171 .file_icon:before {
168 .icon(@fa-var-file-o)
172 .icon(@fa-var-file-o)
169 }
173 }
170
174
171 #notebook_toolbar .pull-right {
175 #notebook_toolbar .pull-right {
172 padding-top: 0px;
176 padding-top: 0px;
173 margin-right: -1px;
177 margin-right: -1px;
174 }
178 }
175
179
176 ul#new-menu {
180 ul#new-menu {
177 // align right instead of left
181 // align right instead of left
178 left: auto;
182 left: auto;
179 right: 0;
183 right: 0;
180 }
184 }
181
185
182 .kernel-menu-icon {
186 .kernel-menu-icon {
183 padding-right: 12px;
187 padding-right: 12px;
184 width: 24px;
188 width: 24px;
185 content: @fa-var-square-o;
189 content: @fa-var-square-o;
186 }
190 }
187
191
188 .kernel-menu-icon:before {
192 .kernel-menu-icon:before {
189 content: @fa-var-square-o;
193 content: @fa-var-square-o;
190 }
194 }
191
195
192 .kernel-menu-icon-current:before {
196 .kernel-menu-icon-current:before {
193 content: @fa-var-check;
197 content: @fa-var-check;
194 }
198 }
195
199
196 #tab_content {
200 #tab_content {
197 padding-top: @page-header-padding;
201 padding-top: @page-header-padding;
198 }
202 }
199
203
200 #running {
204 #running {
201 .panel-group{
205 .panel-group{
202 .panel {
206 .panel {
203 margin-top: 3px;
207 margin-top: 3px;
204 margin-bottom: 1em;
208 margin-bottom: 1em;
205
209
206 .panel-heading {
210 .panel-heading {
207 background-color: @page-backdrop-color;
211 background-color: @page-backdrop-color;
208 padding-top: @dashboard_tb_pad;
212 padding-top: @dashboard_tb_pad;
209 padding-bottom: @dashboard_tb_pad;
213 padding-bottom: @dashboard_tb_pad;
210 padding-left: @dashboard_lr_pad;
214 padding-left: @dashboard_lr_pad;
211 padding-right: @dashboard_lr_pad;
215 padding-right: @dashboard_lr_pad;
212 line-height: @btn_mini_height;
216 line-height: @btn_mini_height;
213
217
214 a:focus, a:hover {
218 a:focus, a:hover {
215 text-decoration: none;
219 text-decoration: none;
216 }
220 }
217 }
221 }
218
222
219 .panel-body {
223 .panel-body {
220 padding: 0px;
224 padding: 0px;
221
225
222 .list_container {
226 .list_container {
223 margin-top: 0px;
227 margin-top: 0px;
224 margin-bottom: 0px;
228 margin-bottom: 0px;
225 border: 0px;
229 border: 0px;
226 border-radius: 0px;
230 border-radius: 0px;
227
231
228 .list_item {
232 .list_item {
229 border-bottom: 1px solid @table-border-color;
233 border-bottom: 1px solid @table-border-color;
230
234
231 &:last-child {
235 &:last-child {
232 border-bottom: 0px;
236 border-bottom: 0px;
233 }
237 }
234 }
238 }
235 }
239 }
236 }
240 }
237 }
241 }
238 }
242 }
239 }
243 }
240
244
241 .delete-button {
245 .delete-button {
242 display: none;
246 display: none;
243 }
247 }
244
248
245 .duplicate-button {
249 .duplicate-button {
246 display: none;
250 display: none;
247 }
251 }
248
252
249 .rename-button {
253 .rename-button {
250 display: none;
254 display: none;
251 }
255 }
252
256
253 .shutdown-button {
257 .shutdown-button {
254 display: none;
258 display: none;
255 }
259 }
General Comments 0
You need to be logged in to leave comments. Login now