').append(
+ $("").addClass("save-message")
+ .text(i18n.msg._('Path must be relative to the notebook root directory'))
+ ).append(
+ $(" ")
+ ).append(
+ $('').attr('type','text').attr('size','25')
+ .addClass('form-control').attr('placeholder', 'Enter notebook name here')
+ );
+ var d = dialog.modal({
+ title: 'Save As',
+ body: dialog_body,
+ keyboard_manager: this.keyboard_manager,
+ notebook: this,
+ buttons: {
+ Cancel: {},
+ Save: {
+ class: 'btn-primary',
+ click: function() {
+ var nb_name_or_path = d.find('input').val();
+ var nb_name = nb_name_or_path.split("/").slice(-1).pop();
+ var ext = utils.splitext(nb_name)[1];
+ if (ext && ext!== '.ipynb') {
+ d.find('.save-message').append(' ').append(i18n.msg._(
+ "Notebook files should have extension .ipynb")
+ );
+ } else if (!that.test_notebook_name(nb_name)) {
+ d.find('.save-message').append(' ').append(i18n.msg._(
+ "Notebook names must have 1 or more characters and can contain any characters except :/\\")
+ );
+ }
+ else if (ext === '') {
+ nb_name_or_path += '.ipynb';
+ }
+ that.copy_notebook(nb_name_or_path);
+ return false;
+ }
+ },
+ },
+ open : function () {
+ /**
+ * Upon ENTER, click the OK button.
+ */
+ d.find('input[type="text"]').keydown(function (event) {
+ if (event.which === keyboard.keycodes.enter) {
+ d.find('.btn-primary').first().click();
+ return false;
+ }
+ });
+ d.find('input[type="text"]').focus().select();
+ }
+ });
+ }
+
/**
* Update the autosave interval based on the duration of the last save.
*
@@ -2911,11 +2967,12 @@ define([
* Make a copy of the current notebook.
* If the notebook has unsaved changes, it is saved first.
*/
- Notebook.prototype.copy_notebook = function () {
+ Notebook.prototype.copy_notebook = function (new_name) {
var that = this;
var base_url = this.base_url;
var w = window.open('', IPython._target);
var parent = utils.url_path_split(this.notebook_path)[0];
+ new_name = new_name || '';
var p;
if (this.dirty && this.writable) {
p = this.save_notebook(true);
@@ -2923,7 +2980,7 @@ define([
p = Promise.resolve();
}
return p.then(function () {
- return that.contents.copy(that.notebook_path, parent).then(
+ return that.contents.copy(that.notebook_path, parent, new_name).then(
function (data) {
w.location = utils.url_path_join(
base_url, 'notebooks', utils.encode_uri_components(data.path)
diff --git a/notebook/static/services/contents.js b/notebook/static/services/contents.js
index 0425959b3e0..fe56eb051e6 100644
--- a/notebook/static/services/contents.js
+++ b/notebook/static/services/contents.js
@@ -186,17 +186,23 @@ define(function(requirejs) {
return utils.promising_ajax(url, settings);
};
- Contents.prototype.copy = function(from_file, to_dir) {
+ Contents.prototype.copy = function(from_file, to_dir, name='') {
/**
* Copy a file into a given directory via POST
- * The server will select the name of the copied file
+ * If name is not given, the server will select the name of the
+ * copied file
*/
var url = this.api_url(to_dir);
+ var body = {copy_from: from_file};
+
+ if (name) {
+ body.copy_to = name
+ }
var settings = {
processData : false,
type: "POST",
- data: JSON.stringify({copy_from: from_file}),
+ data: JSON.stringify(body),
contentType: 'application/json',
dataType : "json",
};
diff --git a/notebook/templates/notebook.html b/notebook/templates/notebook.html
index 647b92850a1..aff23447666 100644
--- a/notebook/templates/notebook.html
+++ b/notebook/templates/notebook.html
@@ -88,7 +88,10 @@