Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Finding absolute start/end position of the node at a given position. #505

Closed
theefer opened this issue Dec 8, 2016 · 7 comments
Closed

Comments

@theefer
Copy link
Contributor

theefer commented Dec 8, 2016

Given the simple document p("hello ", link("world")), is there a way using the API to find the start/end absolute positions (position 7/12) in the document of the link, given a position within it (eg wo|rld i.e. position 9)?

The use case is to implement a link editor, so that when the user clicks on a link, I can determine the start and end position of the link so that it can be edited or removed. I've spent the last two hours playing with all the prosemirror-model APIs I could find, but no luck extracting those positions 😢

I feel like I must be missing something obvious in the docs, or else there may be a totally different way of going about solving this...

@marijnh
Copy link
Member

marijnh commented Dec 8, 2016

childAfter and childBefore are probably relevant. I.e. if you have a resolved position inside the link (but not at the very start), doing $pos.parent.childBefore($pos.parentOffset) will give you the link node and its local offset.

@marijnh marijnh closed this as completed Dec 8, 2016
@theefer
Copy link
Contributor Author

theefer commented Dec 8, 2016

Thanks.

This works for the simple example I provided, because the local position is the same as the absolute one, but I should have provided a more representative example.

Given something like: doc(bullet_list(list_item(p("foo")), list_item(p("hello", link("world")))))

From what I see, the solution you suggested would provide the local position within the p, but what I was after was the absolute position from the root doc. It would make sense to have to compute the absolute offset by recursively walking up the path of the resolved position, adding up local offsets until I reach the root node, but from what I can see only the immediate parentOffset is recorded, not at each level?

Is finding such absolute positions an anti-pattern? Am I meant to record positions using local offsets and generate a transform for that later on for my use case?

Thanks again for your help!

@marijnh
Copy link
Member

marijnh commented Dec 8, 2016

So add $pos.start(), or compute the difference between the start of the node and the position, $pos.parent.childBefore($pos.parentOffset).offset - $pos.parentOffset and subtract that from $pos.pos

@theefer
Copy link
Contributor Author

theefer commented Dec 9, 2016

Awesome, that did it, thanks a lot for your help!

For reference if anyone needs to do this, here is roughly what my code looks like:

const resolvedPos = doc.resolve(pos);
const parentInfo = resolvedPos.parent.childBefore(resolvedPos.parentOffset);
const linkNode = parentInfo.node;
const linkStartPos = parentInfo.offset;
const posInParent = resolvedPos.parentOffset;
const offsetInLink = posInParent - linkStartPos;
const linkFrom = pos - offsetInLink;
const linkTo = linkFrom + linkNode.nodeSize;

Note that if the same link mark applies to a segment of text that contains another sub-mark (eg italic), more work needs to be done to find the boundaries of the link.

@marijnh
Copy link
Member

marijnh commented Dec 9, 2016

Seeing that this is really a little awkward, I'm adding a textOffset getter (pretty much equivalent to your offsetInLink variable) to resolved positions (since they already store that information), which would reduce this to...

const $pos = doc.resolve(pos)
const linkStart = pos - $pos.textOffset
const linkEnd = linkStart + $pos.parent.child($pos.index()).nodeSize

See ProseMirror/prosemirror-model@e7c4d80

@theefer
Copy link
Contributor Author

theefer commented Dec 10, 2016

Brilliant, thanks @marijnh!

@hmoreras
Copy link

If you need the selection range of the paren node of the current selection you can do it this way:

state.selection.$to.before( state.selection.$from.depth - 1), state.selection.$to.after(state.selection.$from.depth - 1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants