Release 0.6.0

I’ve just tagged version 0.6.0. This is the one where linear positions land, which means a lot of breaking changes.

0.6.0 (2016-04-13)

Breaking changes

Positions in the document are now represented by integers, rather than Pos objects. This means that every function parameter, return value, or property that used to be a Pos is now a number instead.

Be extra wary about functions that return an optional position—0 is a valid position now, so if your code is just checking if (pos) ..., it’ll break when getting a 0.

The countCoordsAsChild, handleClick, handleDoubleClick, and handleContextMenu methods on node types, which used to take a path as an array of numbers, now get a single number pointing at the node’s position in the document instead.

The "selectNodeLeft/Right/Up/Down" commands, which were a hack to make node selection work, are now no longer exposed as commands.

The key bindings for block types changed again, due to the old ones still clashing with default OS X bindings. They are now prefixed with Shift-Ctrl (rather than Shift-Cmd on OS X).

Nodes lost the size and width properties, and now expose a nodeSize property instead, which is the total size of the node. The size attribute on fragments changed meaning to point at the total size of the fragment’s children (rather than their count).

Node iterators are gone, and replaced by index-based access using the childCount property and the child and maybeChild accessors.

The chunkBefore and chunkAfter methods on nodes are replaced by a childBefore and childAfter method with the same role but slightly different semantics.

Node.slice now returns a Slice. Node.sliceBetween is gone. The method that just returns a reduced Node is now called cut (and also present on fragments).

The node and fragment methods splice, append, close, replaceDeep, and the old replace are gone. Document manipulation is now best done in one shot using the new replace method, which replaces a range of the document with a Slice.

Since we are no longer using arrays of numbers to find nodes, Node.path is gone. To find out what an integer position points at, use Node.resolve, and then inspect the resulting ResolvedPos object.

Node.nodeAfter is now called Node.nodeAt. It does mostly the same thing, except that it now takes a number position.

Node.nodesBetween passes a start position for the current node, rather than mutable path, to its callback. Node.inlineNodesBetween is gone, since it is now very easy to do something like that with nodesBetween. Node.descendants is a new shorthand that iterates over all descendant nodes.

Fragments lost their toArray, map, and some methods, and otherwise mostly mirror the changes in the Node type.

The constant empty fragment now lives under Fragment.empty rather than emptyFragment.

Steps lost their pos property. They now only store a from and to (as numbers rather than Pos objects).

The result of applying a step no longer contains a position map. Those can be derived from a step without applying it now (using the posMap method). A failing step no longer returns null. Rather, a step result contains either an error message or an updated document.

You no longer need to provide a position map when inverting a step.

The Mappable interface’s map method now returns a plain position, instead of a MapResult. Use the mapResult method if you need the additional information.

Position maps have gotten much simpler, and are created differently now.

Transforms no longer silently ignore failing steps unless you explicitly tell them to by using the maybeStep method. The step method, along with most of the other transformation methods, will raise an error when they can’t be applied.

Transform.replace now takes a Slice object, rather than a full replacement document with start and end positions.

Bug fixes

An unsoundness in the collaborative editing algorithm’s handling of replace steps has been fixed.

The SVG icons now also work when you have a <base> tag on your page.

Fix select-all on Firefox.

Fix crash in history compression.

Properly handle HTML sublists not wrapped in an <li> tag.

Prevent Ctrl-Enter and Ctrl-Backspace on OS X from messing up our document.

Handle the case where a clipboardData object is present but doesn’t actually work (iOS).

New features

ProseMirror.flush now return a boolean indicating whether it redrew the display.

New data type, Slice, which represents a piece of document along with information about the nodes on both sides that are ‘open’ (can be joined to adjacent nodes when inserting it into a document).

The new "transformPasted" event can be used to transform pasted or dragged content, as a parsed Slice.

The Node.eq predicate can now be used to determine whether two nodes are equal.

The join and lift transform methods now have a silent parameter to suppress exceptions when they can not be applied.

The type parameter to setNodeType now defaults to the node’s current type.

toDOM, toHTML, and toText now accept Fragment objects as well as nodes.

List items now have lift and sink commands.

1 Like

And inclusiveRight and inclusiveLeft properties on MarkType!

You’re right, not sure how I missed that patch. Fixed in this patch (note that there’s only inclusiveRight, not Left).

Is there an easy way to convert a node child index to position?

Is the index all you have? If you have a ResolvedPos, just use its before method. If not, you’ll have to loop over the children before the index, sum their nodeSize, and add that to the position at the start of the node.

Out out curiosity what’s driving this change? It’s more performant?

It simplifies some code tremendously, namely position mapping and writing transform steps (or even just anything that needs to reason about the way positions change as the result of a step). These were such a pain to do before that I was finding myself unable to pull off a refactor of the transform code I had planned. If the person who came up with an API can’t write code against it, it’s probably not realistic to expect others to do so.

The new approach is probably also more performant, but I haven’t profiled that.

1 Like