jupyter / notebook

Jupyter Interactive Notebook
https://jupyter-notebook.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
11.58k stars 4.85k forks source link

Feature Request: Add wysiwyg html editor as input cell type #4516

Open gutow opened 5 years ago

gutow commented 5 years ago

Currently, I am aware of Jupyter notebooks support for three CLI type interfaces to generate html output in the notebook:

  1. cell magic %%html followed by raw html in the cell.
  2. python html output:
    from IPython.display import HTML
    htmlstr = '<div>...</div>'
    display(HTML(htmlstr))
  3. markdown cells.

To improve ease of use and flatten the learning curve a bit, I think it would be a good idea to add a WYSIWYG html editor such as https://github.com/tinymce/tinymce as an input cell option in addition to markdown. I think this should not be too hard, but am not familiar enough with the client server communication protocols to be sure. If this is relatively easy and somebody can point me in the right direction, I might be able to do this. I have done a significant amount of interface programming for Plone and Sagemath.

jasongrout commented 5 years ago

@gutow, good to hear from you!

I'd suggest looking into writing a jlab plugin to provide such an editor for JupyterLab. I'll try to dig up some links to good places to start in the next day or two (please ping me if I haven't replied...)

jasongrout commented 5 years ago

(but please note that the input format really is markdown, not html like Sage - so it would need to be something like ProseMirror that writes out markdown)

gutow commented 5 years ago

@jasongrout Hi!

Based on my understanding of the Jupyterlab architecture, I think this would work best inline in the notebook. My understanding is that Jupyterlab embeds the notebook by wrapping it in extensions. I am also unclear about your comment that the "real format" is markdown. Ultimately to be displayed in the browser based notebook html is generated. I am suggesting a new kind of input cell that has a WYSIWYG html editor. Upon being run the editor is hidden and the html is displayed. From examining the DOM I believe that is essentially what the markdown cells do, but the server has to translate the markdown into html. I am suggesting a case where the server would not have to do any translation, just recording.

I am not sure how much time I have for this. How hard would it be to get a SOC intern?

gutow commented 5 years ago

Have started working on this, but am having trouble with getting the WYSIWYG editor registered properly on a DOM element. I can do proof of method in a notebook, but then the keyboard manager slurps up a lot of the input. Trying to duplicate the cell type code for textcells I am having trouble getting the WYIWYG editor recognized in the JS code, does this have to do with the order things are loaded?

jasongrout commented 5 years ago

I am also unclear about your comment that the "real format" is markdown.

The Jupyter notebook cells are in markdown format. That is how they are stored and interpreted. Lucky for you, though, you can use html in markdown.

I can do proof of method in a notebook, but then the keyboard manager slurps up a lot of the input.

Again, I would suggest using JupyterLab, which is designed to extend with new components. My guess is that embedding a different wysiwyg editor in Jupyter notebook will not be as natural.

If you want to try doing this in JupyterLab, I'd suggest opening an issue in the JupyterLab repo for help.

gutow commented 5 years ago

I have looked a little at JupyterLab. I think the basic ideas are good, but it also looks as if it is getting pretty heavy as far as JS that is running, even compared to the notebook. As my first use case is on systems running on lower powered ARM processors and GPUs, I would like to keep the JS load down as low as possible. JupyterLab also appears to be in more flux than I will have time to keep up with after the summer is over. That is why I think doing this at the notebook level is better for me. I am discovering that the notebook is not quite as modular as it could be. I would like to see a more modular version of the notebook ultimately be embedded in JupyterLab, where the cell type defines the editor and no editor actions are handled or processed at the notebook level. At this point, my understanding of the JupyterLab architecture is that is layers on top of the notebook. Am I misunderstanding how JupyterLab functions?

gutow commented 5 years ago

My son (a likely future computer science major) and I have made considerable progress. As of today we have a working prototype using the Quill WYSIWYG editor. We still have code cleanup, organizing and tweaking the css, adding Quill to the build tool chain, getting the downgrading of the necessary nbformat working, and unit tests to build.

Sorry about the closing and reopening below. I have an overly sensitive touch pad badly located on the netbook I am typing this on.

jasongrout commented 5 years ago

As my first use case is on systems running on lower powered ARM processors and GPUs

I (somewhat) regularly use JupyterLab on Raspberry Pi 3B to teach kids how to program. It works great, if that counts as a "lower powered ARM processor".

I am discovering that the notebook is not quite as modular as it could be.

That is part of the reason for JupyterLab.

I would like to see a more modular version of the notebook ultimately be embedded in JupyterLab, where the cell type defines the editor and no editor actions are handled or processed at the notebook level. At this point, my understanding of the JupyterLab architecture is that is layers on top of the notebook. Am I misunderstanding how JupyterLab functions?

JupyterLab is a completely new javascript application that includes a new rewrite of a notebook. However, the notebook component, and even the cell and output components, are completely standalone and can be used outside of JupyterLab. See the examples at https://github.com/jupyterlab/jupyterlab/tree/master/examples/notebook and https://github.com/jupyterlab/jupyterlab/tree/master/examples/cell, for example. People have used these components to build single notebook-on-a-page interfaces, or even just single cells on a page (like SageCell).

jasongrout commented 5 years ago

See https://github.com/jupyterlab/jupyterlab/blob/master/CONTRIBUTING.md#build-and-run-the-stand-alone-examples for how to build those standalone examples.

gutow commented 5 years ago

Jason (@jasongrout),

Now that we have something working in the old notebook, I am considering how to port to JupyterLab as I do like the basic idea. Because I am new to ts-script I will need some real direction as to where things are buried in the code and the actual structure of the working server <-> notebook communications. Below are some of my initial questions:

  1. At this point, from reading the setup.py, it still appears that JupyterLab pulls in and uses the old Jupyter notebook (backend maybe?). Am I misreading that or is that just a bit of legacy code that has not been pulled out?
  2. The notebook json validation in the old notebook had to be updated to make the new cell type save without complaining. Does JupyterLab use the same validation tools? From a quick scan of the code it was not obvious to me how this is handled. Can you point me to where notebook json validation occurs?
  3. Another issue that needs clarification for my 1st use case is the status of gui widgets that pass data back and forth to the kernel. The code I use for communicating with Pi A-to-D boards presently depends on ipywidgets for user setting of parameters. It appears from the developer docs that these are not yet well supported. Is that true?
  4. Another isssue is that the code appears to be significantly heavier browser js code than the old notebook. Because my use case requires running both the back end and the browser on the same Raspberry Pi, I do have issues with the total load on the system. Clearly I will have to try the A-to-D code with JupyterLab to see.

Thanks for any additional direction you can provide.

jasongrout commented 5 years ago
1. At this point, from reading the setup.py, it still appears that JupyterLab pulls in and uses the old Jupyter notebook (backend maybe?). Am I misreading that or is that just a bit of legacy code that has not been pulled out?

It only uses the Jupyter notebook tornado server, not the frontend code.

2\. The notebook json validation in the old notebook had to be updated to make the new cell type save without complaining. Does JupyterLab use the same validation tools? From a quick scan of the code it was not obvious to me how this is handled. Can you point me to where notebook json validation occurs?

Did you change python or js code?

3\. Another issue that needs clarification for my 1st use case is the status of gui widgets that pass data back and forth to the kernel. The code I use for communicating with Pi A-to-D boards presently depends on ipywidgets for user setting of parameters. It appears from the developer docs that these are not yet well supported. Is that true?

ipywidgets is fully supported in JupyterLab 1.0

4\. Another isssue is that the code appears to be significantly heavier browser js code than the old notebook. Because my use case requires running both the back end and the browser on the same Raspberry Pi, I do have issues with the total load on the system. Clearly I will have to try the A-to-D code with JupyterLab to see.

When I mentioned using jlab on a Raspberry Pi, I meant I was running both the server and browser on the pi (hooked up to a screen - completely standalone). I thought it worked rather well.

gutow commented 5 years ago

Jason (@jasongrout), Thanks for the clarifications. That sounds really good. I will have to set up JupyterLab and see what happens.

We had to change python and json validation code in jupyter/nbformat to add an additional cell type, plus some of the hard coded version information in the notebook file handling python. The updated validation checks that the format is appropriate for the WYSIWYG rich text editor we chose, but could be made less restrictive. Otherwise I think we touched only javascript, css (less) and some template files. A major issue was that the old notebook is not cell editor agnostic. We had to write some code to deal with specific calls to codemirror from the notebook. Is codemirror tied to the JupyterLab notebook as tightly?

jasongrout commented 5 years ago

We had to change python and json validation code in jupyter/nbformat to add an additional cell type, plus some of the hard coded version information in the notebook file handling python.

The server-side changes would still be needed, since we are using exactly the same server backend.

A major issue was that the old notebook is not cell editor agnostic. We had to write some code to deal with specific calls to codemirror from the notebook. Is codemirror tied to the JupyterLab notebook as tightly?

JupyterLab has the concept of an abstract "editor", and provides a default codemirror editor as an implementation. You can implement a different editor that implements the same interface and it should work well.

gutow commented 5 years ago

Video of what we've implemented so far can be seen attached to the request for feedback posted on the Jupyter discussion list.