'Road to 0.9.0' development meeting

Now that 0.8.0 is out, it’s time to plan what’s next. If you want to collaborate in that discussion, and can make it to our gitter channel next Tuesday, 2016-06-21 at 14:00 UTC, you are very welcome to join.

Some upcoming priorities are:

  • Table support

  • Splitting the library into smaller modules

  • Performance testing: setting up benchmarks, solving bottlenecks, and having performance regression tests

  • In-document widget support

If anything else comes to mind, or you want to help further define what the above efforts should look like, drop by.

To your timezone: Event Time Announcer - ‘Road to 0.9.0’ development meeting

Unfortunately I won’t be able to make it to the development meeting so I’m sharing a few thoughts here:

  • Can’t wait for table support!
  • Regarding library splitting, I commented on the other thread RFC: Splitting the library into packages
  • I haven’t run into any performance problems yet, but setting up benchmarks and regression tests sounds like a good idea to keep it that way going forward

Regarding widgets I can think of the following possible requirements:

  • The way a widget/control is rendered should be up to the user (as with menus)
  • I could imagine rendering overlays which need to keep their positions in sync with the underlying node (e.g. rendering the controls of a node at the right side of the editor at the height of the node)
  • When handling events of a widget (e.g. click on a control), their should be a way to easily get the corresponding node position (this will probably often be used to update the node attributes using setNodeType)

Something else that I’m interested in, which could potentially be achieved using widgets depending on the implementation:

  • Being able to render a handle for a node to allow drag and drop operations via that handle. An example would be rendering a handle to the left of a paragraph when hovering over the paragraph and allowing the paragraph to be dragged and dropped to another position in the document using that handle.
  • A similar use case would be to select a node by clicking on such a handle.

I hope this helps!

Thanks for the feedback!

We’re kicking this off now. If you have time, do drop in.

Unfortunately I couldn’t make the meeting, but read over the chat and made some notes. It was great having the discussion on gitter, even as a passive reader after the event!

Tables

Some features that I didn’t see mentioned that I’m interested in:

  • Multi-cell selection in tables.
  • row selection
  • column selection
  • n×m cell selection

The use-cases I’m interested in for multi-cell selection:

  • applying cell background color
  • bolding content
  • deleting content from multiple cells
  • copying cells from one table, pasting in another

I’ve been considering the merits of having a document model that’s different to the DOM structure. In the case of tables, having a sparse data structure like the following is simplier to mutate than the DOM structure:

{
    rows: ["row-jen", "row-kwn", "row-fjw"],
    cols: ["col-rhw", "col-hrb", "col-2qn"],
    cells: {
        "row-jen,col-rhw": "top left cell content",
        "row-fjw,col-2qn": "bottom right cell content",
    }
}

e.g. inserting a row or column is an O(1) operation (rather than proportional to the number of columns or rows in the table).

I’m not sure how this could/should be done in ProseMirror.

Widgets

A few questions:

  1. Would widgets wouldn’t contribute to the “tokens” count (i.e. pos). If you insert multiple widgets at the same pos, how is ordering determined?
  2. What are some of the items you imagine might be passed in options?
  3. If a user copies a portion of content that includes some widgets, in some cases you wouldn’t want those widgets to be included in the clipboard content. I think there might just be a CSS property that prevents a node from being part of a selection?

Decomposing the library

I’m seriously considering moving the history and the built-in commnands/keymap out of the core as well

This is really interesting to me, as I’m in a position where I might need to integrate with an OT collab module rather than ProseMirror’s. I realise this is pretty hand-wavy but pulling history out seems like it could only be a good thing for that scenario.

Reactive DOM API

As an aside, I’ve been thinking really hard about how to make the editor work together more smoothly with reactive-style apps

Love the idea from a developer perspective, my only concern would be about performance in large documents.

Performance

In the context of performance, if anyone has a large, non-confidential collection of steps that build up a big document in a real-world way, I’d love to use that as test data

For the initial performance tests I did with Draft vs Prose, I used large HTML docs like: The Project Gutenberg eBook of Frankenstein, by Mary Wollstonecraft Shelley It contains marks like emphasis and quotes.

Hi Bradley, thanks for the feedback.

Tables are definitely going to remain modeled along the same lines as the rest of the content. A consistent document structure is absolutely necessary to keep this project workable. I’m not really sure why the complexity of inserting a column is a concern – if you have tables large enough that adding a column is a performance problem, you’re going to run into other issues first (DOM bloat, for example).

Multi-cell selections are not on the roadmap at this point. I agree they’d be nice to have, but they’d be rather complex to do, and other things have priority in the near future.

Widgets would not contribute to the token count. That is purely determined by the document, which these are not part of. Order would be determined by creation order, I guess, or maybe you can set an option to influence it.

One option that comes to mind is whether they stick to the content to the left of them or to the right (i.e. when content gets inserted at their position, do they end up before or after it). There’ll probably also things like whether mouse events in the widget should be handled by ProseMirror or not.

Widgets won’t be copied when the content around them is copied, though it seems that this might be difficult to enforce on platforms that don’t have a working clipboard API (Edge, iOS). If you meant the user-select css property, that unfortunately doesn’t prevent the content from actually copied when a selection is made across it. Copy-pasting inside of ProseMirror can be made to work by setting an attribute on widgets and ignoring those when pasted, but that won’t help when pasting into other apps.

To give you a bit of background to my question, all this comes from our experience with our existing editor that uses OT for collaboration. In our scenario the structure I described makes it very easy to create deltas made up of OT vocabulary primitives.

We found that when trying to use a DOM-like structure for tables in OT, it was impossible to express the deltas using OT vocabulary in a manner that’s resistant to corruption. If a user adds a column at the same time as another adding a row, the final table structure would be missing cells.

An example might illustrate it better:

tr1
├── td11
└── td12

tr2
├── td21
└── td22

User 1 inserts a row above – “insert row with 2 cells”

tr0
├── td01
└── td02

tr1
├── td11
└── td12

tr2
├── td21
└── td22

User 2 inserts a column after – “step in, skip 2, insert cell; skip 1, step in, skip 2, insert cell”

tr1
├── td11
├── td12
└── td13

tr2
├── td21
├── td22
└── td23

Merged result:

tr0
├── td01
└── td02

tr1
├── td11
├── td12
└── td13

tr2
├── td21
├── td22
└── td23

This led me to explore the idea of an editor using a model that’s different to the rendered structure. As with anything there’s pros/cons, but hopefully this gives you a bit of background to my question :slight_smile:.

Of course with ProseMirror’s collab the vocabulary is much more domain specific, so it’s possible to correctly rebase the changes and avoid corruption.


For me this is definitely something we’ll need eventually, but I don’t have an opinion yet as to whether it’s something the editor core should be concerned with, or if it’s adequate to live in a specialised node/plugin. When thinking about this I always come back to wanting a native solution, I should take a look if there’s any activity from standards working groups on it.

Yep this is consistent with my thinking too.

Ahh my bad! Good to know.

(One more reason to prefer ProseMirror’s built-in collaboration mechanism, no?)

There’s benefits on both sides.

I think one really really nice to have feature for me would be having a vocabulary for steps/deltas that’s generic enough that new content structures (e.g. tables) can be added to the editor without needing changes to the collab server.

The premise being that rich new node types could be written by outsiders as plugins and if designed correctly would “just work” with existing infrastructure.

To be honest I still need to dig into and get a proper understanding of the step vocabulary in ProseMirror — this is on my todo list :). Maybe the ProseMirror collab vocabulary is flexible enough to cover the majority of cases already.

ProseMirror take on this is that such types would come with custom Step subclasses, distributed with the types, and the server would have to load those to be able to run those changes. As you’ve seen with OT, trying to generalize these is really hard, and so far I’m happy with how easy it’s been to define things like add/remove column or changing the depth of a section and its subsection in an atomic step on top of my system.

1 Like

Stumbled across https://github.com/google/incremental-dom which looks pretty interesting. Might be something that could be leveraged for DOM interactions in the future.

Hey there, just wanted to ask what the current status regarding the 0.9.0 release is (I’m especially interested in table support :slight_smile: ). Are there any large breaking changes we can expect for this release?

That’s a really good question, and I hope I manage to answer it in this thread. (Short version: sorry, I got distracted by architecture astronauting)