diff --git a/notebook/static/tree/js/notebooklist.js b/notebook/static/tree/js/notebooklist.js index 79e2b822c..995b8fb13 100644 --- a/notebook/static/tree/js/notebooklist.js +++ b/notebook/static/tree/js/notebooklist.js @@ -129,6 +129,7 @@ define([ // Bind events for action buttons. $('.rename-button').click($.proxy(this.rename_selected, this)); + $('.move-button').click($.proxy(this.move_selected, this)); $('.shutdown-button').click($.proxy(this.shutdown_selected, this)); $('.duplicate-button').click($.proxy(this.duplicate_selected, this)); $('.delete-button').click($.proxy(this.delete_selected, this)); @@ -550,6 +551,15 @@ define([ $('.rename-button').css('display', 'none'); } + // Move is only visible when one item is selected, and it is not a + // running notebook. + // TODO(nhdaly): Add support for moving multiple items at once. + if (selected.length === 1 && !has_running_notebook) { + $('.move-button').css('display', 'inline-block'); + } else { + $('.move-button').css('display', 'none'); + } + // Shutdown is only visible when one or more notebooks running notebooks // are selected and no non-notebook items are selected. if (has_running_notebook && !(has_file || has_directory)) { @@ -765,6 +775,7 @@ define([ } }); input.focus(); + // Highlight the filename (up to the filetype suffix) in the input field. if (input.val().indexOf(".") > 0) { input[0].setSelectionRange(0,input.val().indexOf(".")); } else { @@ -774,6 +785,71 @@ define([ }); }; + NotebookList.prototype.move_selected = function() { + var that = this; + + // TODO(nhdaly): Support moving multiple items at once. + if (that.selected.length !== 1){ + return; + } + + var item_path = that.selected[0].path; + var item_name = that.selected[0].name; + var item_type = that.selected[0].type; + + // Open a dialog to enter the new path, with current path as default. + var input = $('').attr('type','text').attr('size','25').addClass('form-control') + .val(utils.url_path_join('/', that.notebook_path)); + var dialog_body = $('
').append( + $("

").addClass("rename-message") + .text('Enter new destination directory path for '+ item_type + ':') + ).append( + $("
") + ).append(input); + var d = dialog.modal({ + title : "Move "+ item_type, + body : dialog_body, + buttons : { + Cancel : {}, + OK : { + class: "btn-primary", + click: function() { + // Construct the new path using the user input and its name. + var new_path = utils.url_path_join(input.val(), item_name) + that.contents.rename(item_path, new_path).then(function() { + that.load_list(); + }).catch(function(e) { + dialog.modal({ + title: "Move Failed", + body: $('

') + .text("An error occurred while moving \"" + item_name + "\" from \"" + item_path + "\" to \"" + new_path + "\".") + .append($('
') + .addClass('alert alert-danger') + .text(e.message || e)), + buttons: { + OK: {'class': 'btn-primary'} + } + }); + console.warn('Error durring moving :', e); + }); + } + } + }, + // TODO: Consider adding fancier UI per Issue #941. + open : function () { + // Upon ENTER, click the OK button. + input.keydown(function (event) { + if (event.which === keyboard.keycodes.enter) { + d.find('.btn-primary').first().click(); + return false; + } + }); + // Put the cursor at the end of the input. + input.focus(); + } + }); + }; + NotebookList.prototype.delete_selected = function() { var message; if (this.selected.length === 1) { diff --git a/notebook/static/tree/less/tree.less b/notebook/static/tree/less/tree.less index ef733a540..d19dedd91 100644 --- a/notebook/static/tree/less/tree.less +++ b/notebook/static/tree/less/tree.less @@ -327,6 +327,10 @@ ul#new-menu { display: none; } +.move-button { + display: none; +} + .shutdown-button { display: none; } diff --git a/notebook/templates/tree.html b/notebook/templates/tree.html index 966242b14..acdf97141 100644 --- a/notebook/templates/tree.html +++ b/notebook/templates/tree.html @@ -31,6 +31,7 @@ data-terminals-available="{{terminals_available}}"
+