Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Propose exporting DOM position mapping #6

Closed
wants to merge 1 commit into from

Conversation

marijnh
Copy link
Member

@marijnh marijnh commented Apr 11, 2018

This proposal adds methods to EditorView instances to map between DOM positions and ProseMirror document positions, and to get the DOM node that represents a given document node in the view.

Rendered RFC

@bradleyayers
Copy link
Contributor

This is definitely an issue that I've hit before and welcome these new APIs.

posAtDOM(domPos: {node: dom.Node, offset: number}) → number

The need for an object with both node and offset isn't immediately obvious to me as a consumer. I suspect this may deserve and a more in-depth explanation for why this data structure is appropriate (versus just node), and an examples showing real-world usage would be great (e.g. in DOM event handlers). My first reaction was "why isn't it just posAtDom(dom.Node) → number?".

In the past I've wanted to use an API like this to do:

const firstParagraph = editorView.root.querySelector("p");
const pos = editorView.posFromDom(firstParagraph);

In this case I'd be satisfied for pos to be the position before the paragraph node in the document. It's not clear to me what value of offset I'd need to plug in to achieve that.

@marijnh
Copy link
Member Author

marijnh commented Apr 12, 2018

My first reaction was "why isn't it just posAtDom(dom.Node) → number?".

What would that refer to, the position before the node, after the node, or somewhere inside it? Many positions (such as those in text) can't be described like this at all. See the way the DOM selection uses focusNode/focusOffset for a precedent.

In the past I've wanted to use an API like this to do:

And that's exactly the kind of things that you really shouldn't be doing—for any information that you can get out of the ProseMirror document, you should not use the DOM. It's inefficient and error prone. Just use editorView.state.doc.descendants to find your paragraph (along with its position).

@bradleyayers
Copy link
Contributor

What would that refer to, the position before the node, after the node, or somewhere inside it? Many positions (such as those in text) can't be described like this at all. See the way the DOM selection uses focusNode/focusOffset for a precedent.

Referring to the position before the node would be fine, so that Node#nodeAt can be used to to easily get a reference to the node.

The scenario where this came up in the past was having a hover menu rendered over a node using a widget decoration, and wanting to find the doc node when a button is triggered. For me the first approach I tried was to feed the DOM event target (or an ancestor of) into a ProseMirror API to find the node. I then wanted to dispatch a transaction to change that node (or plugin state associated with that node). In plugins with state containing references to nodes, I store the position before the node.

In the end this approach didn't pan out, and I ended up using EditorView#posAtCoords or storing positions as data attribute on menu DOM nodes to do the association.


Aside: It occurred to me that the documentation for Node.nodeAt might be a little ambiguous in its use of the phrase starting at, given "start" in ResolvedPos#start means something else (unless I'm misinterpreting what Node.nodeAt does).

@kapouer
Copy link

kapouer commented Apr 12, 2018

I'm already using quite heavily docView's domFromPos and posFromDOM. Pretty cool to see it become supported api.

marijnh added a commit to ProseMirror/prosemirror-model that referenced this pull request Apr 13, 2018
marijnh added a commit to ProseMirror/prosemirror-view that referenced this pull request Apr 24, 2018
FEATURE: The new [`EditorView.posAtDOM`
method](##view.EditorView.posAtDOM) can be used to find the document
position corresponding to a given DOM position.

FEATURE: The new [`EditorView.nodeDOM`
method](##view.EditorView.nodeDOM) gives you the DOM node that is used
to represent a specific node in the document.

Issue ProseMirror/rfcs#6
@marijnh
Copy link
Member Author

marijnh commented Apr 24, 2018

I've merged this in 4094584 and implemented it in attached patch.

@marijnh marijnh closed this Apr 24, 2018
@adrianheine adrianheine deleted the expose-dom-position-mapping branch October 8, 2018 11:08
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants