Skip to content
This repository

Htmlnotebook #705

Merged
merged 232 commits into from over 2 years ago

5 participants

Brian E. Granger Fernando Perez Min RK Matthias Bussonnier Stefan van der Walt
Brian E. Granger
Owner

This is the initial version of the notebook and the related notebook format. The main parts of the code that need review are:

  • IPython.nbformat.
  • IPython.frontend.html.notebook
  • IPython.core.display
and others added some commits July 13, 2011
Brian E. Granger Fixing code to assume msg_type and msg_id are top-level.
* I have gone through and looked for instances of ['msg_type'] and
  ['msg_id'] and tried to make sure that I added ['header'] so
  pull the values out of the header.
* But there are many cases where I can't tell if the dict is the
  full message or the header already. This is especially true
  of the msg_id in the parallel db parts of the code.
* Tests pass, but this is scary.
1bc3aac
Brian E. Granger Renaming unpack_message to unserialize and updating docstrings. efa1f33
Brian E. Granger Fixing docstrings and a few more places for msg_id/msg_type. d86d45f
Brian E. Granger Adding html notebook subpackage. 0494d13
Brian E. Granger Initial draft of HTML5/JS/CSS3 notebook. adcfbf8
Brian E. Granger Adding shift-enter support. 9e95afe
Brian E. Granger Fixing selection and focus logic. 04da04e
Brian E. Granger Added placeholder text for TextCell. 927f44b
Brian E. Granger Adding preventDefault to shift-up/down events. d7f2add
Brian E. Granger Work on the server side of the html notebook. 398f176
Brian E. Granger Basic server for htmlnotebook working. b7248bf
Brian E. Granger Initial reply handling implemented along with css fixes. 0bfc754
Brian E. Granger Make the main notebook div auto scroll. 5a8489e
Brian E. Granger Adding tests for zmq.session. a09b42a
Brian E. Granger More tests for Session.send/recv. b95a185
Brian E. Granger Fixing messaging docs to reflect msg_type in header. fa7cc46
Brian E. Granger Adding temp refs to msg_type to prevent nested dict gets. e5d9e2c
Brian E. Granger Fixing bug in ipkernel.py related to msg_type refactoring. e4a965d
Brian E. Granger Fixing another bug in msg_type refactoring. f0d2271
Brian E. Granger Server side of file based notebook store implemented. 5dc428b
Brian E. Granger Initial template for notebook browser. a2dd039
Brian E. Granger Added message to help users open notebook. 74b8ea8
Brian E. Granger Updating jquery UI and themes. 1497e96
Brian E. Granger Fixing main toolbar area and cleaning up jquery themes. 339135b
Brian E. Granger Different clients now share a single zmq session.
Previously, each client (browser window) would open its own set
of ZMQ sockets to a kernel. Now one master set of connections
to the kernel is created and all clients share those connections.
In some ways, this simplifies the URL design.

I have also made kernel_ids server-side created.
2ad3ee4
Brian E. Granger Minor changes to notebook css. df52f21
Brian E. Granger Interrupt and restart work for kernels. 7731a50
Brian E. Granger Cleaned up kernel action interface.
* Using POST rather than GET.
* Using simple URLs rather than a query string.
* Using a regexp to match the action.
9fe1c2c
Brian E. Granger Status monitoring added to notebook.
* Busy == red
* Idle == gray
* Restarting == black
1f5c4be
Brian E. Granger Fixes to notebook scrolling and layout.
We are now using the flexible box model, so the layout won't work
on IE9, but it already doesn't work on IE9 because of WS support.
2050714
Brian E. Granger Tweaking and cleanup of notebook.css.
* Adjusted font sizes for improved readability.
* Got rid of unused css attributes and styles.
* Changed font of Title to Verdana.
169110d
Brian E. Granger Further font adjustments to the notebook.
* Using Fernando's recommended monospaced font list.
* Increased tool/tab menus to 10 pt.
3b1715e
Brian E. Granger Work on the notebook's code cell.
* Cleaned up the js code for creating the code cell.
* Added a div around the input text area to allow the text area
  to have a width of 100%.
* Added CodeCell.toJSON.
5d9b6e7
Brian E. Granger Basic notebook saving and loading.
* The logic in the server and javascript frontend is there for
  a basic JSON notebook format with a .ipynb extension.
* To save a new notebook: "%notebook save filename.ipynb"
* To save a notebook that is already saved: "%notebook save"
* To load a notebook from the cwd: "notebook load filename.ipynb"
2607443
Brian E. Granger Initial latex printing for sympy and fixes to autogrow. 68db752
Brian E. Granger Refactoring of the output and display system.
* LaTeX rendering now works.
* Font's are reworked in the css style sheet.
* Testing on FF and Chrome.
9e126bc
Brian E. Granger Fixes to the latex rendering by adjusting the MathJax config. 6c644c6
Brian E. Granger Basic exception display in the notebook is working. bffb119
Brian E. Granger Added basic styling to text cells. 9447eb0
Brian E. Granger Cells call grow by hand when they reload from JSON. a563b92
Min RK include html frontend in packages/package_data
chmod +x ipython-notebook script
e6b3e5b
Brian E. Granger Shift-Enter only selects the next cell if it is a CodeCell. e341cf4
Brian E. Granger Fine tuning of notebook styles.
* Padding added to L/R of notebook div (40px).
* Margin added to T/B of cells (15px).
* Margin added to T of output div (15px).
* More elements using border-box layout mode.
e513eb9
Brian E. Granger Adding logic to look for CDN version of MathJax and fallback to local. 5e55e20
Brian E. Granger Added note about tornado version to main script. ff6dc82
Brian E. Granger Minor fix to sympy latex printing.
* \dag is converted to \dagger.
5d05db0
Brian E. Granger Adding new notebook examples.
* Many that use sympy's quantum computing (github master required)
* One from Fernando Perez that does text analysis.
7877585
Brian E. Granger Minor changes to text_analysis notebook example. 1ff5a82
Brian E. Granger Updating notebook examples, and notebook js/html. 264b061
Brian E. Granger General CSS cleanup.
* Created layout.css for common layout related mixins.
* monospace is the default font for now.
e3dc236
Brian E. Granger CodeMirror code editing added.
* codemirror2 repo has been added to IPython.
* Custom coloring used to match the qtconsole.
f5911d3
Brian E. Granger Better handling of up/down arrows for CodeCells. e270403
Brian E. Granger Much improved nagivation for the notebook cells.
* Up/Down arrow now used to navigate cells.
* For text cells, shift-enter renders, enter edits.
c14e651
Brian E. Granger Updating notebook examples. c9ad4e8
Brian E. Granger Updating sympy notebook examples. b2aa21f
Brian E. Granger Updating examples notebooks. 0f16a10
Brian E. Granger Adding new density of states notebook example. b55bc76
Brian E. Granger Creating files to new notebook app. 98f7851
Brian E. Granger Fixing import statments in handlers and notebookapp. a94f1fa
Brian E. Granger Initial reorg of files complete.
I have moved things around to get ready for making the notebook
a full blown app, but have not actually made it an app.  That is
next.
02f9051
Brian E. Granger Renaming NotebookApplication to NotebookWebApplication. 8deb465
Brian E. Granger Refactored htmlnotebook session and kernel manager.
* The KernelManager now manages multiple kernels with a uniform
  API.
* The SessionManager now manages the full set of channels+streams
  and the IPython.zmq.session.Session object for a single kernel.
3f3cd92
Brian E. Granger Refactoring the notebook app to support the new config system. 9ce4875
Brian E. Granger Notebook app debugging.
* Logging is now working with a default of INFO.
* Other misc bug fixes.
e051436
Brian E. Granger Work to adapt routers to new Session message protocol. f0ab259
Brian E. Granger More work on updating the notebook zmq forwarding. fd1d84c
Brian E. Granger Updating the notebook to work with the latex master.
* PNG figures are now used for matplotlib.
* NEW msg format is used where msg_type is in the header.
* Session is used for sending/recving.
97f1ce7
Brian E. Granger Splitting notebook.js into muliple files for development ease. 82dfeed
Brian E. Granger Updating main notebook template to use split scripts. 90a9bbc
Brian E. Granger Change unpack_message to unserialize in routers.py. 27afdf3
Brian E. Granger Implemented module and namespace pattern in js notebook. c5b0c06
Brian E. Granger Using $.proxy to clean up callbacks. 73126bf
Brian E. Granger Actually kill old kernels upon restart. 7fc2c96
Brian E. Granger Starting to refactor the notebook layout ad2890a
Brian E. Granger Initial payload handling.
* Syntax highlighting fixed for things like "math?".
* Basic pager is working.
af64139
Brian E. Granger Refactoring pager into its own class. aa37ef2
Brian E. Granger Updating jQuery to 1.6.2 and jQuery UI to 1.8.14.
I have also added a focus.html files for testing focus related
events.
8766e94
Brian E. Granger Adding note about vbox related scroll bugs. ed4b3fd
Brian E. Granger More work updating the notebook to use dynamics resizing. a0257f5
Brian E. Granger Pager is working again. 9262f15
Brian E. Granger More accuract height calculations for the pager collapse/expand. e37fefa
Brian E. Granger Left panel is now working. 450ed2f
Brian E. Granger Improving the scrolling model. 1579023
Brian E. Granger Initial draft of panel section and the cell section working. c6ab30b
Brian E. Granger Minor fixes to fonts and spacing. a7ef503
Brian E. Granger Controls in cell section have a solid layout. 71e8168
Brian E. Granger Help section implemented and working. 0376908
Brian E. Granger Minors fixes and initial work on save widget.
* Fixed width of buttons in left panel.
* Started to create a save widget for the header.
e4683b7
Brian E. Granger Work on save widget, kernel status widget and notebook section. 67aa594
Brian E. Granger Fixing execution related things.
* Extra enter on FF is fixed by hooking into CodeMirror's
  onKeyEvent hook. We now have CodeMirror ignore shift-enter
  completely as we handle it ourselves.
* The cell execution logic in notebook.js has been refactored and
  the Run All/Selected buttons have been hooked up.
f1b3d4a
Brian E. Granger Updating font-sizing to use the YUI protocol. 0c51946
Brian E. Granger Prevent shift-enter from propagating and performing default. d8294f0
Brian E. Granger Colors now working in tracebacks and the pager.
For now I am just converting ANSI color escape sequences to HTML
<span> tags that have css classes for coloring.
00dc27f
Brian E. Granger Added complete method of JS kernel object. 5829983
Brian E. Granger Autocompletion working with CTRL-SPACE. dad53c3
Brian E. Granger CTRL-ENTER now runs a cell in "terminal mode"
In this mode, a new cell is not created after the current cell
is run. Once the cell is run, the current input is cleared, so
it acts just like the terminal.
6a242ba
Brian E. Granger Removing default input prompt number.
In a notebook setting being able to delete and add cells makes it
virtually impossible to correctly guess what the next input
prompt number should be. We now follow the convention that our
prompts look like "In [ ]:" before execution.
b1f1dde
Brian E. Granger Adding nbformat subpackage. 68687d2
Brian E. Granger Notebook now uses tab for autocompletion. 4b71ab3
Brian E. Granger Fixes to terminal mode execution (ctrl-enter). c88117a
Brian E. Granger Hacks to prevent FLOUC (flash of unformatted content). fbddd43
Brian E. Granger Fixing minor resize bug on the Mac. 27379eb
Brian E. Granger Adding Cell.grow back to fix bug.
This can go away once we star to use CodeMirror for TextCells.
8012152
Brian E. Granger Initial draft of more formal notebook format.
* Basic Python notebook uses a simple Struct subclass,
  NotebookNode for representing the notebook components.
* XML and JSON readers/writers work in full round trip manner.
* Python reader/writter works for code cells.
* Everything is tested.
f3a5072
Brian E. Granger Updates to basic notebook format.
* The format now handles multiple output blocks.
* XML now as worksheets, cells and outputs tags.
4b0e672
Min RK support html representations in the notebook frontend
html gets highest priority, because it is the native language
of the frontend.
1cc83a7
Brian E. Granger Full versioning added to nbformat. 0251893
Brian E. Granger Merge branch 'repr_html' of https://github.com/minrk/ipython into min…
…rk-repr_html
a65c2d3
Brian E. Granger Added lib/display.py for extra display related things. c292a9c
Min RK update add_packages for reorganized nbformat 4c2aebb
Brian E. Granger Fixing setupbase.py for nbformat package. 540b3f1
Brian E. Granger Massive work on the notebook document format.
* Finished nbformat work and debugged the versioning API.
* Integrated the nbformat with the notebook. Save/New/Open/Export
  are all now working.
65666c0
Brian E. Granger Merge branch 'htmlnotebook' of github.com:ipython/ipython into htmlno…
…tebook

Conflicts:
	setupbase.py
d77eb2c
Brian E. Granger Implemented basic notebook browser and fixed numerous bugs. 1699c90
Brian E. Granger Implemented delete functionality in nb browser.
* Dialog confirms the notebook delete.
* Notebook element is removed from list upon deletion.
b0243db
Brian E. Granger File upload/import working from notebook browser. 53c7ec7
Brian E. Granger Improvements to file uploaded, mime types and .py reader.
* The .py notebook reader now uses that ast module to split
  a plain python file into blocks. These blocks become cells in
  the notebook.
* Proper mime types are used for xml (application/xml), json
  (application/json) and python (application/x-python).
* Other fixes to file uploading.
8f4eb62
Brian E. Granger Adding kernel/notebook associations. 03eb23c
Brian E. Granger Fixed subtle bug in kernel restarting.
* Old routers were not being shutdown and removed.
* We were incorrectly associating the new kernel with the notebook
  (we were using the *old* kernel_id for this).
* General clean ups in the kernel manager.
708c73e
Brian E. Granger Using beforeunload to save at exit and kill the kernel. 7640e54
Brian E. Granger Added saving and loading of output of all types. 2a85499
Brian E. Granger Starting to rename text cell to html cell. b0e516c
Brian E. Granger New HTMl cell working with CodeMirror editing. 653f157
Brian E. Granger Updating CodeMirror to v 2.12.
For now I am keeping the old codemirror2 directory in here until
we finish debugging the new version.
981bc0c
Brian E. Granger Fixing HTML cell syntax highlighting. 3896ff1
Brian E. Granger Starting work on a Markdown cell. f5f6198
Brian E. Granger Refactoring of text/markdown/rst/html cells. fbce942
Brian E. Granger Reordering Export button and renaming Export->Export As 978f742
Brian E. Granger Markdown cells are now saved and restored in notebooks. a85c3e7
Brian E. Granger Implemented smart autoindenting. 4fb6f61
Brian E. Granger Fixed text cell rendering bug. 8bee5f8
Brian E. Granger Updates to the css style of rendered html text cells. db81ec2
Brian E. Granger Minor fixes to config system for notebook. 89e253a
Brian E. Granger Adding minor help strings for keyboard shortcuts. ddb901b
Brian E. Granger Merge branch 'master' into htmlnotebook
Conflicts:
	setupbase.py
fd892df
Brian E. Granger Updating notebook configuration.
* ipython_notebook_config.py is now created and staged.
* New certfile/keyfile config=True attributes for enabling SSL/TLS.
* Examples of usage added.
* New handling for --ip=*
* Aliases added.
53df0ac
Brian E. Granger Created new notebook magic that can export/convert notebooks.
* %notebook --export foo will export the current IPython history
  to a file foo.ipynb.
* %notebook --format=json foo.ipynb will convert foo.ipynb to
  foo.json.
46fc646
Brian E. Granger Adding initial documentation on the notebook. 1bcb722
Brian E. Granger Reducing/adjusting the padding of cells to make the notebook more
compact.

* Reduced padding between cells from 15px to 5px.
* Prompt width is now dynamic to grow/shrink as the prompt number
  increases in width.
* Reduced padding between input and output from 15px to 5px.
b633a93
Brian E. Granger Updates to the display system.
* New publish_* functions created in IPython.core.displaypub.
* A raw=True argument has been added to the display_* functions
  in IPython.core.display.
* Display object classes such as Html, Png, etc. have been added
  to IPython.core.display to make it easier to diplay raw data
  from the internet.
b84d895
Brian E. Granger Finishing display system work.
* Added image/jpeg MIME type to notebook format, the core display
  logic and the notebook.
* Finished HTML, SVG, Image, Math, Javascript, JSON classes.
08ef328
Brian E. Granger Autoindentation fixed and enabled by default. eaf692f
Brian E. Granger %loadpy works in the notebook and bug with inline plotting fixed. 1de26e1
Brian E. Granger Fixing padding of output cells. b85982d
Brian E. Granger Added note about imports in IPython.__init__. 1d01468
Brian E. Granger Added collapsed field to the code cell. 1c4a699
Brian E. Granger HTML/Markdown cells no longer saved their rendered output. 31ac0f3
Brian E. Granger Adding time delay to show the notebook saving more clearly. 40d4a55
Brian E. Granger New .py notebook format implemented. 7debcc4
Brian E. Granger Adding tracebacks, evalue and etype to the nbformat and notebook. 3669962
Brian E. Granger HTML output cells are now styled with the rendered_html class. df0ed78
Brian E. Granger Disabling auto-save at exit. 453bf75
Brian E. Granger Clear all output is implemented. 31e9da5
Brian E. Granger Major refactor of kernel connection management in the notebook.
* Full kernel heartbeating is working.
* Connections between the notebook and server and now created
  a new each time there is a WebSocket connection. Each channel is
  also handled separately. This dramatically simplifies the
  server code and makes for a more scalable system.
5bad195
Brian E. Granger Merge branch 'master' into htmlnotebook cc6010e
Brian E. Granger Fixing bug that caused plots to not be saved.
CodeCell.append_mime_type needed a default element.
f5c5121
Brian E. Granger Autotry additional ports if 8888 if already in use. d1499b6
Brian E. Granger Browser window title follows the name of the notebook. 1786348
Brian E. Granger Added a notebook dirty flag that is used when exiting page. fb55a88
Brian E. Granger Notebook id removed from the notebook format. a86896d
Brian E. Granger Updating notebook examples to current format. bee9c06
Brian E. Granger Fixing latex rendering bug. feaba3c
Brian E. Granger A single tab-completion match is now automatically selected. 49fa32f
Brian E. Granger Fixing tab completion edge cases. 2d7e32b
Brian E. Granger Adding additional whitespace at botton of notebook for TAB comp. 95590c1
Brian E. Granger Code cell gets focused after "To Code" is triggered. 54eeb77
Brian E. Granger Export works with filenames having spaces.
* The fix was to put the filename in double quotes in the
  Content-Disposition header.
* Export As/Clear All have been renamed to Export and Clr All
09a90c4
Brian E. Granger I like ClearAll better than Clr All. 50206b2
Brian E. Granger Pager is not activated if the pager text is empty.
* Things like asdf.*? used to open the pager even though there
  was nothing to show.
baf6e69
Brian E. Granger Date is properly removed from JSON reply before WebSocket forward.
* Both the header and parent_header have a date field that cannot
  be json serialized. This field is just removed for now, but
  in the future, we will covert the date to a ISO8601 field.
* Better error handling around this code has also been added
  to prevent the server from crashing due to malformed messages.
b796f24
Brian E. Granger Kernel/notebook mapping is removed when a kernel dies.
* Previously, when a kernel died due to an external cause, the
  notebook/kernel mapping was not removed, so the kernel would
  be resused even though it was dead.
* The heartbeat now properly removes the notebook/kernel mapping.
a1dcaf6
Brian E. Granger WebSocket url is now passed to browser when a kernel is started. 856b17f
Brian E. Granger Removing old CodeMirror version. 56475d6
Fernando Perez
Owner

Just a note for anyone interested in helping us with this PR: all feedback is welcome, but obviously on something of this size we're not going to do a line-by-line nitpick. Furthermore, the functionality developed here is so absolutely essential that there's no question this is going in, even though we are fully aware it needs more tuning.

But if anyone is interested in participating in the review and you spot any problems, by all means point them out so we can fix things before it goes into trunk and gets more users. Bonus points if you help us out by actually installing it and running it. You simply need to have at least tornado 2.0 installed, and if you are using Firefox, turn on websockets by going to the about:config page, filtering on 'websocket' and turning both options to true by double clicking on them. Once you do this, you can run it via

ipython notebook --pylab=inline

or you can omit the --pylab support if you don't want plots. pylab is only used for figures, the notebook works fine without numpy/matplotlib.

IPython/__init__.py
@@ -43,6 +43,14 @@ sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
43 43
 from .config.loader import Config
44 44
 from .core import release
45 45
 from .core.application import Application
  46
+# Todo: Should these be imported here? We need to rethink what is imported in
  47
+# this module.
  48
+#from .core.display import (
  49
+#    display, display_pretty, display_html, display_latex,
  50
+#    display_png, display_jpeg, display_svg, display_json,
  51
+#    display_javascript, HTML, SVG, Math, Image, JSON,
  52
+#    Javascript, Pretty
  53
+#)
4
Fernando Perez Owner
fperez added a note August 15, 2011

I suggest that instead, we have a top-level 'display' module that simply imports the things we want to expose (possibly including core and lib).

In general, I think we should follow a pattern where things meant for public use should be at most one module deep:

from IPython.foo import bar, baz

even if these top-level modules are mostly just pass-throughs that load from deeper parts of the hierarchy. But these will be the ones we consider public, and things deeper in are more subject to change. That way we only have to explain to people in normal docs and instructions these top-level namespaces, leaving the rest as 'an implementation detail'.

Brian E. Granger Owner
ellisonbg added a note August 16, 2011

Or do you think all of the user facing stuff (not just the display stuff) should go into a single module? Right now there is IPython.embed and we will definitely have more and more user facing code.

Fernando Perez Owner
fperez added a note August 16, 2011

How about we just remove these for now from the merge, since the organization of the public api is really a separate issue from the notebook code, and we make sure that in the next month or two when the dust on the notebook settles, we set up a time to discuss the public api with a clear head. I don't think there's major hurry in getting that right, so as long as we do it before too long (say a few months, in the 0.12-0.13 timeframe), we'll be OK. And we can calmly review all the pieces we want exposed, and think about the cleanest way to do so...

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/core/display.py
((99 lines not shown))
99 145
 
100  
-def display_latex(*objs):
  146
+    Parameters
  147
+    ----------
  148
+    objs : tuple of objects
  149
+        The Python objects to display, or if raw=True raw JPEG data to
  150
+        display.
  151
+    raw : bool
  152
+        Are the data objects raw data or Python objects that need to be
  153
+        formatted before display? [default: False]
  154
+    """
  155
+    raw = kwargs.pop('raw',False)
  156
+    if raw:
  157
+        for obj in objs:
  158
+            publish_png(obj)
2
Fernando Perez Owner
fperez added a note August 16, 2011

Should this really be png, or was it meant to be jpeg?

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/core/displaypub.py
@@ -56,7 +56,7 @@ class DisplayPublisher(Configurable):
56 56
             Any metadata for the data.
57 57
         """
58 58
 
59  
-        if not isinstance(source, str):
  59
+        if not isinstance(source, (str,unicode)):
2
Fernando Perez Owner
fperez added a note August 16, 2011

This should use instead

isinstance(source, basestring)

which covers all the cases and is py3-compatible out of the box.

Brian E. Granger Owner
ellisonbg added a note August 16, 2011

Pushing a fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Brian E. Granger Fixing two minor things for review.
* Using basestring for str, unicode test.
* png->jpeg in display_jpeg.
bedc0f7
IPython/core/magic.py
@@ -48,6 +48,7 @@ from IPython.core.error import UsageError
48 48
 from IPython.core.fakemodule import FakeModule
49 49
 from IPython.core.profiledir import ProfileDir
50 50
 from IPython.core.macro import Macro
  51
+from IPython.core import magic_arguments
51 52
 from IPython.core import page
2
Fernando Perez Owner
fperez added a note August 16, 2011

These two lines can probably just be

from IPython.core import magic_arguments, page

so we don't accumulate extra unnecessary separate import lines.

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/core/profileapp.py
@@ -193,6 +193,15 @@ class ProfileCreate(BaseIPythonApplication):
193 193
             pass
194 194
         else:
195 195
             apps.append(IPythonQtConsoleApp)
  196
+        try:
  197
+            from IPython.frontend.html.notebook.notebookapp import IPythonNotebookApp
  198
+        except Exception:
  199
+            # this should be ImportError, but under weird circumstances
  200
+            # this might be an AttributeError, or possibly others
  201
+            # in any case, nothing should cause the profile creation to crash.
  202
+            pass
3
Fernando Perez Owner
fperez added a note August 16, 2011

Which are reasonable reasons to get errors in this import? Just missing dependencies? Shouldn't we at least throw up a warning with the exception info if there's an error, so that users are made aware of a problem? Or at least throw the warning in the non-ImportError cases, if ImportError is expected to happen somewhat normally...

Min RK Owner
minrk added a note August 16, 2011

This is copied from the qt code, which could raise a variety of errors, depending on PySide/PyQt versions, etc., and there's nothing at all that should prevent profile creation. It is unlikely that the notebook app will raise anything other than ImportError, but always possible. A warning on non-ImportErrors would be appropriate, or just a debug or info-level message in every circumstance.

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

I am passing on ImportError and log.debug(exec_info=True) on anything else now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Fernando Perez fperez commented on the diff August 16, 2011
IPython/extensions/sympyprinting.py
@@ -48,6 +48,14 @@ def print_png(o):
48 48
     png = latex_to_png(s)
49 49
     return png
50 50
 
  51
+
  52
+def print_latex(o):
  53
+    """A function to generate the latex representation of sympy expressions."""
  54
+    s = latex(o, mode='equation', itex=True)
  55
+    s = s.replace('\\dag','\\dagger')
  56
+    return s
3
Fernando Perez Owner
fperez added a note August 16, 2011

To avoid extra unnecessary assignments, the whole function can be written as:

return latex(o, mode='equation', itex=True).replace('\\dag','\\dagger')

I know one-liners can get unreadable, but in this case it doesn't seem that bad to me and it saves some time and memory (and I actually find the short form very readable). Not a big deal though, I'll leave the final decision up to you.

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

I am going to leave this as it is extremely likely we will discover additional transforms that need to happen on the latex.

Fernando Perez Owner
fperez added a note August 17, 2011

no prob.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Fernando Perez
Owner

Note: the help links at the bottom aren't working for me now, and I'm pretty sure a few days ago I had tried them and they did work. You may want to have a look...

Min RK
Owner

Can you add the favicon from ipython.org (https://github.com/ipython/ipython-website/blob/master/_static/favicon.ico), so tornado doesn't constantly print favicon warnings?

Fernando Perez
Owner

Brian, note that right now, the test suite fails with:

======================================================================
ERROR: test_session_manager (IPython.frontend.html.notebook.tests.test_kernelsession.TestKernelManager)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/fperez/usr/lib/python2.6/site-packages/IPython/frontend/html/notebook/tests/test_kernelsession.py", line 30, in test_session_manager
    sm = km.create_session_manager(kid)
AttributeError: 'KernelManager' object has no attribute 'create_session_manager'

----------------------------------------------------------------------
Ran 14 tests in 0.205s
IPython/frontend/html/notebook/notebookapp.py
((184 lines not shown))
  184
+        """Return the WebSocket URL for this server."""
  185
+        if self.certfile:
  186
+            prefix = u'wss://'
  187
+        else:
  188
+            prefix = u'ws://'
  189
+        return prefix + self.ws_hostname + u':' + unicode(self.port)
  190
+
  191
+    def parse_command_line(self, argv=None):
  192
+        super(IPythonNotebookApp, self).parse_command_line(argv)
  193
+        if argv is None:
  194
+            argv = sys.argv[1:]
  195
+
  196
+        self.kernel_argv = list(argv) # copy
  197
+        # kernel should inherit default config file from frontend
  198
+        self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
  199
+        # scrub frontend-specific flags
5
Fernando Perez Owner
fperez added a note August 16, 2011

This logic should be slightly changed: list.remove(x) is a slow, O(n) operation.

Instead lines 193-199 should be replaced with:

# scrub frontend-specific flags
nb_flags = set(notebook_flags) # O(1) checks
self.kernel_argv = [a for a in argv if not(a.startswith('-') and a.lstrip('-') in nb_flags)]
# kernel should inherit default config file from frontend
self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
Min RK Owner
minrk added a note August 16, 2011

Don't forget to make a similar update on the aliases section as well, since your proposal only handles half of it. I presume this code is copied from my block in the qtconsole app, so the inefficient code is probably mine.

Also, remember that this is argv, so we are talking about an O(n) operation on a list usually of length 2, and maybe up to 10 in extreme cases, with a theoretical upper bound of every IPython configurable, which is O(100). And list.remove can only be called at most once for each notebook flag, which is a very small number.

Fernando Perez Owner
fperez added a note August 16, 2011

Yes, I know these things are small, but I just like to use the right approaches when feasible (esp. when the right approach doesn't have a larger cost than the simpler one nor is it more obscure to read). I actually find the alternate code more readable than the original, FWIW :)

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

With your approach the filtering of both the flags and aliases has to be done at the same time, which makes the list comprehension incomprehensible. I am leaving the same. Also, as Min said, there is 0 performance reason to make this change when O(n) == O(10).

Fernando Perez Owner
fperez added a note August 17, 2011

no problem. My definition of readable list comprehensions often differs from that of most people ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Fernando Perez
Owner

When printing, we need some kind of word wrap solution. Right now if you print a long list, you simply get a very, very wide page with a huge horizontal scrollbar. If this isn't an easy fix now, let me know and we'll just open an issue for it.

IPython/frontend/html/notebook/notebookapp.py
((231 lines not shown))
  231
+            self, self.kernel_manager, self.notebook_manager, self.log
  232
+        )
  233
+        if self.certfile:
  234
+            ssl_options = dict(certfile=self.certfile)
  235
+            if self.keyfile:
  236
+                ssl_options['keyfile'] = self.keyfile
  237
+        else:
  238
+            ssl_options = None
  239
+        self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
  240
+        if ssl_options is None and not self.ip:
  241
+            self.log.critical('WARNING: the notebook server is listening on all IP addresses '
  242
+                              'but not using any encryption or authentication. This is highly '
  243
+                              'insecure and not recommended.')
  244
+        for i in range(10):
  245
+            try:
  246
+                port = self.port + i
2
Fernando Perez Owner
fperez added a note August 16, 2011

I would rewrite this logic as:

        from random import randint
        n = 50 # max number of attempts, keep reasonably large
        for port in [self.port] + [self.port + randint(-2*n, 2*n) for i in range(n)]:
            try:
                self.http_server.listen(port, self.ip)
            except socket.error, e:
                if e.errno != errno.EADDRINUSE:
                    raise
                self.log.info('The port %i is already in use, trying another random port.' % port)
            else:
                self.port = port
                break

In cluster-type environments and other shared resources, it will be very easy to find the range of ports 8888-8898 to be occupied. This approach tries 50 random ports centered around 8888, which is far more likely to succeed after one or two tries, and will in general be faster for users than manually walking the list every time.

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/frontend/html/notebook/notebookmanager.py
((34 lines not shown))
  34
+    allowed_formats = List([u'json',u'xml',u'py'])
  35
+
  36
+    # Map notebook_ids to notebook names
  37
+    mapping = Dict()
  38
+    # Map notebook names to notebook_ids
  39
+    rev_mapping = Dict()
  40
+
  41
+    def list_notebooks(self):
  42
+        """List all notebooks in the notebook dir.
  43
+
  44
+        This returns a list of dicts of the form::
  45
+
  46
+            dict(notebook_id=notebook,name=name)
  47
+        """
  48
+        names = os.listdir(self.notebook_dir)
  49
+        names = [name.split(u'.')[0] \
2
Fernando Perez Owner
fperez added a note August 16, 2011

final backslash not needed here (the open list makes it ok to continue without backslash)

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/frontend/html/notebook/notebookmanager.py
((66 lines not shown))
  66
+        return notebook_id
  67
+
  68
+    def delete_notebook_id(self, notebook_id):
  69
+        """Delete a notebook's id only. This doesn't delete the actual notebook."""
  70
+        name = self.mapping[notebook_id]
  71
+        del self.mapping[notebook_id]
  72
+        del self.rev_mapping[name]
  73
+
  74
+    def notebook_exists(self, notebook_id):
  75
+        """Does a notebook exist?"""
  76
+        if notebook_id not in self.mapping:
  77
+            return False
  78
+        path = self.get_path_by_name(self.mapping[notebook_id])
  79
+        if not os.path.isfile(path):
  80
+            return False
  81
+        return True        
2
Fernando Perez Owner
fperez added a note August 16, 2011

The last three lines should just be

return os.path.isfile(path)

Both clearer and faster.

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/frontend/html/notebook/notebookmanager.py
((110 lines not shown))
  110
+        if not os.path.isfile(path):
  111
+            raise web.HTTPError(404)
  112
+        info = os.stat(path)
  113
+        last_modified = datetime.datetime.utcfromtimestamp(info.st_mtime)
  114
+        try:
  115
+            with open(path,'r') as f:
  116
+                s = f.read()
  117
+                try:
  118
+                    # v2 and later have xml in the .ipynb files.
  119
+                    nb = current.reads(s, 'xml')
  120
+                except:
  121
+                    # v1 had json in the .ipynb files.
  122
+                    nb = current.reads(s, 'json')
  123
+                    # v1 notebooks don't have a name field, so use the filename.
  124
+                    nb.name = os.path.split(path)[-1].split(u'.')[0]
  125
+        except:
2
Fernando Perez Owner
fperez added a note August 16, 2011

I'm a little worried that any python error here will map to a 404, because it will make debugging problems in this kind of code hard, no? Would it be reasonable to have some kind of debug flag in which the 404 page is returned but with traceback info in it of some kind? I know the cgitb module from the stdlib helps format tracebacks in html, so perhaps it could be used here.

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

I will open an issue for this. I think we can send back JSON data describing the error. I don't think we want to send back an actual traceback, but some sort of message that the browser can use to programatically determine the source of the error. I am not too worried about it because I have used HTTP error codes that are themselves almost completely descriptive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Fernando Perez fperez commented on the diff August 16, 2011
IPython/frontend/html/notebook/notebookmanager.py
((121 lines not shown))
  121
+                    # v1 had json in the .ipynb files.
  122
+                    nb = current.reads(s, 'json')
  123
+                    # v1 notebooks don't have a name field, so use the filename.
  124
+                    nb.name = os.path.split(path)[-1].split(u'.')[0]
  125
+        except:
  126
+            raise web.HTTPError(404)
  127
+        return last_modified, nb
  128
+
  129
+    def save_new_notebook(self, data, name=None, format=u'json'):
  130
+        """Save a new notebook and return its notebook_id.
  131
+
  132
+        If a name is passed in, it overrides any values in the notebook data
  133
+        and the value in the data is updated to use that value.
  134
+        """
  135
+        if format not in self.allowed_formats:
  136
+            raise web.HTTPError(415)
3
Fernando Perez Owner
fperez added a note August 16, 2011

Again, regarding debuggability: is it possible to include some information about the error? Something like raise web.HTTPError(415, "invalid format %s supplied" % format)?

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

In this case 415 means "Unsupported Media Type", which is basically the information we would return. I have been quite careful to return error codes that are specific.

Fernando Perez Owner
fperez added a note August 17, 2011

ok, thanks for the info

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/frontend/html/notebook/notebookmanager.py
((131 lines not shown))
  131
+
  132
+        If a name is passed in, it overrides any values in the notebook data
  133
+        and the value in the data is updated to use that value.
  134
+        """
  135
+        if format not in self.allowed_formats:
  136
+            raise web.HTTPError(415)
  137
+
  138
+        try:
  139
+            nb = current.reads(data, format)
  140
+        except:
  141
+            if format == u'xml':
  142
+                # v1 notebooks might come in with a format='xml' but be json.
  143
+                try:
  144
+                    nb = current.reads(data, u'json')
  145
+                except:
  146
+                    raise web.HTTPError(400)
1
Fernando Perez Owner
fperez added a note August 16, 2011

Same comment as above regarding extra info in these exceptions, and the same will apply wherever there's one of these (I won't add it on every line, but the idea stands).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Fernando Perez fperez commented on the diff August 16, 2011
IPython/frontend/html/notebook/static/css/base.css
((8 lines not shown))
  8
+
  9
+body {
  10
+    background-color: white;
  11
+    /* This makes sure that the body covers the entire window and needs to
  12
+       be in a different element than the display: box in wrapper below */
  13
+    position: absolute;
  14
+    left: 0px;
  15
+    right: 0px;
  16
+    top: 0px;
  17
+    bottom: 0px;
  18
+    overflow: hidden;
  19
+}
  20
+
  21
+
  22
+div#header {
  23
+    /* Initially hidden to prevent FLOUC */
3
Fernando Perez Owner
fperez added a note August 16, 2011

just curious, what is FLOUC??

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

Flash of Unformatted Content.

Fernando Perez Owner
fperez added a note August 17, 2011

thanks. I'm learning :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Fernando Perez fperez commented on the diff August 16, 2011
IPython/frontend/html/notebook/static/jquery/js/jquery.autogrow.js
... ...
@@ -0,0 +1,42 @@
  1
+/*
  2
+ * Auto Grow Textarea Plugin
  3
+ * by Jevin 5/11/2010
  4
+ * http://www.technoreply.com/autogrow-textarea-plugin/
  5
+ *
  6
+ * Modified by Rob G (aka Fudgey/Mottie)
  7
+ *  - Converted into a plugin
  8
+ *  - Added ability to calculate approximate # cols when textarea is set to 100%
  9
+ *
  10
+ * Simplified by Brian Granger on 5/2/2011
5
Fernando Perez Owner
fperez added a note August 16, 2011

Just curious, is this already in upstream or are these your local changes? I just want to make sure that if we have local changes to upstream libraries, it's easy to update upstream versions and still know what our changes were to reapply them if needed.

Brian E. Granger Owner
ellisonbg added a note August 17, 2011

We are not using this anymore, but I don't think these changes should go back upstream. The logic that was in there originally was fine, but we just needed different logic because of our particular needs.

Fernando Perez Owner
fperez added a note August 17, 2011

So now, we could use 100% upstream? If that's the case, then we should update our tree to be the pure upstream one, so it's clear there are no extra changes of our making.

Brian E. Granger Owner
ellisonbg added a note August 17, 2011
Fernando Perez Owner
fperez added a note August 17, 2011

ok, sounds good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Fernando Perez

Is a naked print a good idea here? If so, then at least we should do

from __future__ import print_function

at the top and use print() instead, so the 2to3 changes are minimized.

Owner

Since it's one of the few things 2to3 handles well, making the from __future__ import print_function change manually, really has zero benefits as far as I know, and is primarily a cause for annoyance.

Owner

I guess I'm just getting used to using print as a function everywhere in anticipation of the transition to 3, so it doesn't bother me much. But I agree that it's not a big deal, and I have no problem if it stays as-is.

Fernando Perez
Owner

In ipython / IPython / nbformat / v2 / nbbase.py I think it would be good to have a little explanation of the format in the top-level docstring, that provides an overview of how the format is strucutred. It will help anyone diving into the code to have a big picture understanding. It doesn't need to be much, just a paragraph or two.

Fernando Perez
Owner

The file ipython / IPython / nbformat / v2 / rwbase.py (the diff was so big that github stopped showing it for the last files, so I have to do these as standalone comments now) should have at least a docstring indicating what it is.

Fernando Perez
Owner

Do we still want to have a standalone ipython-notebook script in scripts?

Fernando Perez
Owner

OK, I'm done. I think all the above are pretty easy to do/fix, and then as far as I'm concerned we can merge!!! This was a spectacular job, I couldn't be more excited about this... Hats off, Brian, you really rock.

Fernando Perez
Owner

Note: there was a commit that contained a test_hist.sqlite in notebook/tests file which shouldn't have been committed. That commit should be purged and we can just rebase the whole thing so the final version when merged doesn't contain that file.

Brian E. Granger
Owner
Fernando Perez
Owner
added some commits August 17, 2011
Brian E. Granger Don't scroll to bottom when last cell is selected. 2c580e7
Brian E. Granger More review changes.
* Favicon.ico is served.
* Test suit now passes.
* Help links work for for me.
* Other changes made to address inline comments.
* The printing of long lines is an extremely subtle issue and I will open an issue for it.
* zmqws.py is completely gone so the naked print is not an issue.
* ipython-notebook removed from scripts.
* Updated copyright and authors of files.
* Fixed missing docstrings in IPython.nbformat.
a661b7c
Brian E. Granger
Owner

OK, I am done with addressing the review comment. It would be good if everyone could run it through its paces one more time though.

and others added some commits August 17, 2011
Brian E. Granger Finish removing ipython-notebook. 2e45b3a
Brian E. Granger Adding code to handle MozWebSocket for FF 6. bf61e42
Brian E. Granger Better WebSocket detection added. 719e65a
Brian E. Granger Better alert message if no WebSockets are detected. 486e84f
Brian E. Granger Removed HTMLCell from UI and added better placeholder logic. eb895bf
Stefan van der Walt Refactor static printing. 968e3fe
Brian E. Granger Modifying CodeMirror focus hack to work better.
I had removed a text area focus event earlier today and that
broke the . key. We are still having problems with CodeMirror
elements gaining focus, but this seems to fix the issue.
7421012
Brian E. Granger Fixing parallel options pricing example. 7777bdd
Brian E. Granger Merge branch 'htmlnotebook_publish' of https://github.com/stefanv/ipy…
…thon into stefanv-htmlnotebook_publish
d5b4ff0
Brian E. Granger Changing notebook uuid algorithm to preserver across sessions. f4c8372
Stefan van der Walt Allow period characters in notebook names. a2b246f
Stefan van der Walt Move glob to global level import. 0e2ee7f
Brian E. Granger Adding page break logic to the print css.
* I have added page-break-inside logic to div.input and
  div.output_area.
* Fixed a bug in CodeCell that was putting the output_area class
  on the wrong div.
898a609
Brian E. Granger Merge branch 'stefanv-htmlnotebook_publish' into htmlnotebook d33fac5
Brian E. Granger Merge branch 'htmlnotebook_list_notebooks' of https://github.com/stef…
…anv/ipython into stefanv-htmlnotebook_list_notebooks
a82fa5d
Brian E. Granger Double clicking on the end space will insert a new cell. cb5364f
Brian E. Granger Better tabindex support. bdb89a7
Brian E. Granger Save button becomes Rename when the notebook name changes. 507621d
Brian E. Granger Help links work on Firefox. 1e2b197
Brian E. Granger Fixing logic for rename behavior. 6d3001f
Brian E. Granger Making JSON the default .ipynb format. cc19c96
Brian E. Granger Converting notebooks to JSON format. 1cfbe5d
Brian E. Granger Notebook upload handles filenames with periods. 33e3025
Min RK minrk commented on the diff August 19, 2011
IPython/frontend/html/notebook/notebookmanager.py
((114 lines not shown))
  114
+        return last_modified, name, data
  115
+
  116
+    def get_notebook_object(self, notebook_id):
  117
+        """Get the NotebookNode representation of a notebook by notebook_id."""
  118
+        path = self.find_path(notebook_id)
  119
+        if not os.path.isfile(path):
  120
+            raise web.HTTPError(404)
  121
+        info = os.stat(path)
  122
+        last_modified = datetime.datetime.utcfromtimestamp(info.st_mtime)
  123
+        with open(path,'r') as f:
  124
+            s = f.read()
  125
+            try:
  126
+                # v1 and v2 and json in the .ipynb files.
  127
+                nb = current.reads(s, u'json')
  128
+            except:
  129
+                raise web.HTTPError(404)
1
Min RK Owner
minrk added a note August 19, 2011

We need a lot more feedback than a 404 here, especially since this isn't even the real page, so users will get exactly no feedback.

The frontend just sticks at 'loading...', and if they enter a name and save, the original corrupt (or xml) notebook is simply erased.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
and others added some commits August 19, 2011
Brian E. Granger Implemented metadata for notebook format. d919e2e
Brian E. Granger Changing CodeMirror-scroll to overflow-y: hidden.
* It seems that our old setting of visible was causing scroll bars
  to appear if font sizes change in Chrome.
* Also changed json -> xml in Download UI.
68889f9
Brian E. Granger Cell collapse/expand is not called "Toggle". 8013d52
Brian E. Granger Reorganize the L panel buttons. b1af148
Brian E. Granger Fixing bug in new metadata implementation. bc7865e
Brian E. Granger All output types are not indented. 9748902
Brian E. Granger Adjusting width of prompt area. 54111d3
Fernando Perez Right-align prompts to remove spurious whitespace. b5134ae
Brian E. Granger Adding keyboard shortcuts. d11e8eb
Brian E. Granger Adding keyboard shortcut help dialog. 7e2eee1
Brian E. Granger Fixing console.log messages related to keyboard shortcuts. 4a3930a
Brian E. Granger Changing prev/next keyboard shortcut to use p/n. 14ae374
Brian E. Granger Fixing XML notebook reader. 5dc0439
Stefan van der Walt Align colons in help dialog. c5f13bc
Brian E. Granger Merge pull request #713 from stefanv/htmlnotebook_help_dialog
Align colons in html notebook help dialog
4408742
Min RK Add utility function for installing mathjax for offline use
from IPython.external.mathjax import install_mathjax

install_mathjax()

* add mathjax destination to gitignore
ff2b547
Min RK update notebook template to prefer offline mathjax 89aca0b
Stefan van der Walt Add code highlighting to markdown cells. d6a97e9
Stefan van der Walt Add prettify license. e591917
Stefan van der Walt Try to match CodeMirror theme. 88fabb9
Fernando Perez Merge pull request #717 from stefanv/htmlnotebook_highlight_markdown
Add source highlighting to markdown snippets, with a theme matching the CodeMirror one we use.

This only highlights source code in blocks that are indented 4 spaces in markdown cells, leaving <pre> blocks alone.  If highlight is desired in <pre> blocks, a further <code> block must be created.

The visual theme matches the one used for CodeMirror as much as possible.
9460984
Fernando Perez Fix above/below keybinding mismatch and rename api to use above/below 9600e07
Min RK underline keyboard shortcut letter on buttons de11baf
Brian E. Granger Merge branch 'mathjax' of https://github.com/minrk/ipython into minrk…
…-mathjax
2213211
Brian E. Granger Adding information about MathJax to notebook install docs. 0bfb0fb
Brian E. Granger Temporary fix for placeholder related CM bug. 876e689
Brian E. Granger ellisonbg merged commit 876e689 into from August 23, 2011
Brian E. Granger ellisonbg closed this August 23, 2011
Matthias Bussonnier

Those 2 bindings seem not to be used. The collapse/expand_pager triggerd seem to be in notebook.js. Am I wrong ? Should I remove them from here ?

Collaborator

Hum, it seem that I'm wrong... I'm not sure t understand how it works then... and what's the difference between those binding and the ones in notebooks.js
Sorry for the noise.

Owner

I don't know why we have both of them, but I did a test and confirm that both are being called when pager.js L62 is run. W can probably move all that logic to pager.js as I don't see anything notebook specific in the notebook.js version. This code was written very early on so I am not surprised it is crusty.

Collaborator

I think the one in pager.js grow/shrink the pager below the separator while the one in notebook.js shrink/grow the height of the notebook area. So it kind of make sens to have function dealing with notebook in notebook..

Owner
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.