Closed blink1073 closed 8 years ago
Notes from discussion this afternoon:
The notebook and cell models should reflect the notebook format exactly, except for metadata which is handled through cursors.
All data is shared, and a change results in a contentChanged(name: string)
signal.
For context, we considered the idea that things like the notebook format scrolled
cell state should really mean initial scrolled state for the cell, which would mean two widgets displaying the same notebook could have different scrolled states for the same cell. However, there are lots of complications like:
So we decided for now that disk state is model state is shared state between widgets. Even if that nbformat state is really UI information.
@jasongrout, commits c80de36 and 457738b reflect the changes to the models.
The comments on metadata cursors about hiding keys defined in the nbformat spec are no longer true (for example in the [get|list]Metadata
functions in cells/model.ts
)
961fbf6 adds a simple toolbar class.
@jasongrout, 1329c90 has a proposal for clipboard and undo/redo handling.
ActiveNotebook
instances would share a clipboard with cell JSON data.IDocumentModel
s) supports a similar API to Google Drive for undo/redo handling.The undo/redo looks okay to me. The clipboard should be application-wide, I think. Perhaps in a separate clipboard service plugin (or perhaps attached to the application?)
Agreed on the app-wide clipboard, I'll think about what that should look like.
As far as undo/redo at the notebook level, I see that as being linked to the events on the observable list of cells. We store the change events and can perform the reverse of the event as needed. For instance, reverting the document would result in an assign()
call and a Replace
event, which could be undone using the arguments of the event in reverse. We can combine events using beginCompoundOperation
.
I don't think a general undo/redo makes sense on the notebook document. For instance, if the last thing that changed was metadata, you may have no visual representation that the metadata changed.
Undo/redo in edit mode would be handled by the CodeMirror instance.
We could punt on doing undo redo for now and just rely on code mirror undo for editing.
Too late ;). I'm about to push a undo/redo capability based on changes to the cells observable list. We'll see where it gets us.
I am also adding a clipboard which is basically the MimeData
type used in drag-drop
for now that is passed to the NotebookPanel
.
See 8e9cd23 for initial implementation. I'm updating next action.ts
to use the undo
actions appropriately, then creating the default toolbar using those actions.
The undo/redo implementation was modeled after: https://github.com/jzaefferer/undo/blob/master/undo.js
Actions updated in bac69bd.
I'm off tomorrow, and will pick this up on Monday. What remains to be done (outside of user acceptance testing) is to create model and widget factories. The notebook widget factory will use a registry for creating notebook instance extensions. At that point we should be ready to add ipywidget support in a follow on PR.
The last commit finishes the initial implementation (including undo/redo handling), but depends on https://github.com/jupyter/jupyter-js-ui/pull/95.
All of the actions that affect cells action.ts
properly support undo and redo.
After #214 is merged, I will rebase and update the console, then this should be good to go.
@blink1073 - a fresh checkout of your branch and building examples gives:
src/index.ts(9,3): error TS2305: Module '"[snip]/nb/examples/console/node_modules/jupyter-js-notebook/lib/index"' has no exported member 'ConsolePanel'.
src/index.ts(9,17): error TS2305: Module '"[snip]/nb/examples/console/node_modules/jupyter-js-notebook/lib/index"' has no exported member 'ConsoleWidget'.
src/index.ts(9,32): error TS2305: Module '"[snip]/nb/examples/console/node_modules/jupyter-js-notebook/lib/index"' has no exported member 'ConsoleModel'.
Is this a known issue?
Yes, because the console is broken in this PR pending #214. I've been building the notebook example from within itself.
I just looked through the notebook undo stuff. A couple of comments:
ObservableUndoableList
or something.note to self: related to undo, here is a page listing a bunch of immutable-type libraries for javascript: https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md
The current implementation is used to allow a snapshot of the cell model. We need to know to call .toJSON
on the cells to serialize them, and we need the model in order to ask it how to create a new cell given cell data.
We could have an ObservableUndoAbleList<IClonable>
where the objects need to be able to clone themselves.
An immutable version of this list would have to store the entire state of the list for each change, as opposed to just the change metadata.
Right, here's a possible sketch
interface IJSONable {
toJSON(): any;
}
class Cell implements IJSONable {
toJSON() {
return {};
}
}
class IOList<T extends IJSONable> {
constructor(factory: (any) => Cell) {
this._factory = factory;
}
private _factory: (any) => Cell;
}
let factory = (any) => {return new Cell();}
let x = new IOList<Cell>(factory);
A smart immutable structure would share substructures where it could, rather than storing the entire list for every change.
Moved undo/redo logic onto the cells list in 5cc1f84.
For future reference, @blink1073 and I discussed the undo/redo, and I think the conclusions were:
Rebased to pull in the changes to the console, will rectify the console this weekend.
This is now "ready", aside from discussion about how we want to handle the contentChanged
signal payload.
It might make more sense to use contentChanged<model: IDocumentModel, IChangeArgs<any>>
and separately add metadataChanged<model: IDocumentModel, IChangeArgs<any>
, where a change to metadata would trigger both signals.
The more I think about it, the more I think contentChanged
should be a void
signal, stateChanged
should be used for simple values that change, and add metadataChanged
because it is a complex value like the cells.
@afshin, I ended up merging the console model into the widget, but left the rest of the pieces largely untouched. Do you mind reviewing console/widget.ts
?
Commit 8a85d23 adds tab completion to the notebook, and 9db2167 adds the ability to select text in the outputs, two of Fernando's concerns.
Thanks! Let's merge and iterate at this point. I'll post an issue with some things that I'm seeing with completion, for example.
I pushed version 0.20.0 with this merged.
If we update jupyter-js-plugins
now, it would be missing the ability to create new notebooks other than the default, switch kernels, and open images. I say we merge https://github.com/jupyter/jupyter-js-ui/pull/97 with just the kernel selector and quick-launch creators and then do a proper update to jupyter-js-plugins
. I will be able to finish those tomorrow.
Fixes #166.