Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New text notebook menu in Jupyter Notebook #525

Merged
merged 4 commits into from
May 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pip install dist/jupytext-XXX.tar.gz

## Jupytext's extension for Jupyter Notebook

Our extension for Jupyter Notebook adds a Jupytext entry to Jupyter Notebook Menu. The code is found at `jupytext/nbextension/index.js`. Instructions to develop that extension are at `jupytext/nbextension/README.md`.
Our extension for Jupyter Notebook adds a Jupytext entry to Jupyter Notebook Menu. The code is found at `jupytext/nbextension/jupytext.js`. Instructions to develop that extension are at `jupytext/nbextension/README.md`.

## Jupytext's extension for JupyterLab

Expand Down
20 changes: 20 additions & 0 deletions jupytext/contentsmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,26 @@ def read_one_file(alt_path, alt_fmt):

return model

def new_untitled(self, path="", type="", ext=""):
"""Create a new untitled file or directory in path

We override the base function because that one does not take the 'ext' argument
into account when type=="notebook". See https://github.com/mwouts/jupytext/issues/443
"""
if type != "notebook":
return super(JupytextContentsManager, self).new_untitled(path)

path = path.strip("/")
if not self.dir_exists(path):
raise HTTPError(404, "No such directory: %s" % path)

model = {"type": "notebook"}
untitled = self.untitled_notebook

name = self.increment_filename(untitled + ext, path)
path = u"{0}/{1}".format(path, name)
return self.new(model, path)

def trust_notebook(self, path):
"""Trust the current notebook"""
if path.endswith(".ipynb") or path not in self.paired_notebooks:
Expand Down
4 changes: 2 additions & 2 deletions jupytext/nbextension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ If you wish to develop this extension, install the javascript file locally with:

```bash
cd jupytext/nbextension
jupyter nbextension install index.js --symlink --user
jupyter nbextension install jupytext.js --symlink --user
jupyter nbextension enable jupytext --user
```

Then, make the desired changes to `index.js` and reload the extension by simply refreshing the notebook (Ctrl+R). In case your OS does not allow symlinks, edit the copy of `index.js` that is actually used by Jupyter (refer to the output of `jupyter nbextension install --user index.js`).
Then, make the desired changes to `jupytext.js` and reload the extension by simply refreshing the notebook (Ctrl+R). In case your OS does not allow symlinks, edit the copy of `jupytext.js` that is actually used by Jupyter (refer to the output of `jupyter nbextension install --user jupytext.js`).
92 changes: 90 additions & 2 deletions jupytext/nbextension/index.js → jupytext/nbextension/jupytext.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
define([
'jquery',
'base/js/namespace',
'base/js/events'
'base/js/events',
'base/js/utils',
], function (
$,
Jupyter,
events
events,
utils
) {
"use strict";

Expand Down Expand Up @@ -231,6 +233,74 @@ define([
);
}

function new_text_notebook(ext='.md') {
// Differences with KernelSelector.prototype.new_notebook from
// https://github.com/jupyter/notebook/blob/
// 6e9256b0641a85baf664e846515085bac2c082a3/notebook/static/notebook/js/kernelselector.js
// - added ext argument
// - kernel_name is the currently selected one
// - "that" replaced with Jupyter

var w = window.open('', IPython._target);
// Create a new notebook in the same path as the current
// notebook's path.
var parent = utils.url_path_split(Jupyter.notebook.notebook_path)[0];
Jupyter.notebook.contents.new_untitled(parent, {type: "notebook", ext:ext}).then(
function (data) {
var url = utils.url_path_join(
Jupyter.notebook.base_url, 'notebooks',
utils.encode_uri_components(data.path)
);
url += "?kernel_name=" + Jupyter.notebook.metadata.kernelspec.name;
w.location = url;
},
function(error) {
w.close();
dialog.modal({
title : i18n.msg._('Creating Notebook Failed'),
body : i18n.msg.sprintf(i18n.msg._("The error was: %s"), error.message),
buttons : {'OK' : {'class' : 'btn-primary'}}
});
}
);
};

function text_notebook_entry(type, title, ext=null) {
return $('<li/>')
.append($('<a/>')
.attr('id', 'new_notebook_' + type)
.text(title)
.attr('title', title)
.data('ext', ext)
.css('width', '280px')
.attr('href', '#')
.on('click', onClickedTextNotebook)
.prepend($('<i/>').addClass('fa menu-icon pull-right'))
);
};

function onClickedTextNotebook(data) {
const ext = $(this).data('ext');
if (ext) { new_text_notebook(ext); };
};

function updateNewScriptNotebookMenu() {
if (Jupyter.notebook.metadata.language_info) {
var script_ext = Jupyter.notebook.metadata.language_info.file_extension;
var language_name = Jupyter.notebook.metadata.language_info.name;
language_name = language_name.charAt(0).toUpperCase() + language_name.slice(1);
var title = language_name + ' script';
$('#new_notebook_script').parent().removeClass('disabled');
$('#new_notebook_script').data('ext', script_ext);
$('#new_notebook_script').attr('title', title);
$('#new_notebook_script').text(title);
}
else {
$('#new_notebook_script').parent().addClass('disabled');
$('#new_notebook_script').data('ext', null);
};
};

var jupytext_menu = function () {
if ($('#jupytext_menu').length === 0) {

Expand Down Expand Up @@ -308,6 +378,24 @@ define([

checkSelectedJupytextFormats();
checkAutosave();

// New Text Notebook menu
var NewTextNotebook = $('<a/>').attr('href', '#')
.addClass('dropdown-toogle')
.attr('data-toggle', 'dropdown')
.attr('aria-expanded', 'false')
.text('New Text Notebook')
.attr('title', 'New Notebook saved as a text file')
.on('mouseover', updateNewScriptNotebookMenu);

var TextNotebooks = $('<ul/>')
.attr('id', 'new_text_notebook_submenu')
.addClass("dropdown-menu");

$('#open_notebook').before('<li id="new_text_notebook"/>');
$('#new_text_notebook').addClass('dropdown-submenu').append(NewTextNotebook).append(TextNotebooks);
TextNotebooks.append(text_notebook_entry('md', 'Markdown', '.md'));
TextNotebooks.append(text_notebook_entry('script', 'Script'));
}
};

Expand Down
2 changes: 1 addition & 1 deletion jupytext/nbextension/jupytext.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ tags:
- script
Link: README.md
Icon: jupytext_menu_zoom.png
Main: index.js
Main: jupytext.js
Compatibility: 5.x, 6.x
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
(
"share/jupyter/nbextensions/jupytext",
[
"jupytext/nbextension/index.js",
"jupytext/nbextension/jupytext.js",
"jupytext/nbextension/README.md",
"jupytext/nbextension/jupytext_menu.png",
"jupytext/nbextension/jupytext_menu_zoom.png",
Expand Down
8 changes: 8 additions & 0 deletions tests/test_contentsmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1702,3 +1702,11 @@ def test_filter_jupytext_version_information_416(nb_file, tmpdir):
assert "jupytext:" in text
assert "kernelspec:" in text
assert "jupytext_version:" not in text


def test_new_untitled(tmpdir):
cm = jupytext.TextFileContentsManager()
cm.root_dir = str(tmpdir)

assert cm.new_untitled(type="notebook", ext=".md")["path"] == "Untitled.md"
assert cm.new_untitled(type="notebook", ext=".md")["path"] == "Untitled1.md"