I’m trying to implement buttons for link, typically remove link and change link destination. Using/patching toggleMark I was able to make it work if the user selects exactly the text that has the link.
However I want to be able to do that when the user when the cursor is in the middle of the link. I think it could be done by modifying the selection to make it match the whole mark before applying the command.
I figured out how to get the active marks, but they come without their positions so I can’t find how to do that. Is there a simple way to do it? Basically get the from/to positions corresponding at the start and end positions of the mark.
You’ll need to inspect the parent node of the cursor, and find the range that the current link covers in that. You could do something like this (untested):
function linkAround(doc, pos) {
let $pos = doc.resolve(pos), parent = $pos.parent
let start = parent.childAfter($pos.parentOffset)
if (!start.node) return null
let link = start.node.marks.find(mark => mark.type.name == "link")
if (!link) return null
let startIndex = $pos.index(), startPos = $pos.start() + start.offset
while (startIndex > 0 && link.isInSet($pos.child(startIndex - 1).marks))
startPos -= $pos.child(--startIndex).nodeSize
let endIndex = $pos.indexAfter(), endPos = startPos + start.node.nodeSize
while (end < parent.childCount && link.isInSet($pos.child(endIndex).marks))
endPos += $pos.child(endIndex++).nodeSize
return {from: startPos, to: endPos}
}
I have found this and Find extents of a mark given a selection. Could this maybe be made into a function in ProseMirror. I am afraid to miss some edge case doing this myself.
I am also looking for a solution like this. So if the cursor is on a link or a single link is fully selected, then it is editable. In current example it is not clear which url it is.
I was testing this out on links that had bold/italics etc in them. This I believe handles those cases. The implementations above don’t work for me due to the endIndex first calculation in some placements of the cursor (directly after bold in a link?). Hope this maybe helps someone else … !
function linkAround(state, pos) {
const $pos = state.doc.resolve(pos);
const { parent, parentOffset } = $pos;
const start = parent.childAfter(parentOffset);
if (!start.node) return null;
const link = start.node.marks.find((mark) => mark.type === state.schema.marks.link);
if (!link) return null;
let startIndex = $pos.index();
let startPos = $pos.start() + start.offset;
let endIndex = startIndex + 1;
let endPos = startPos + start.node.nodeSize;
while (startIndex > 0 && link.isInSet(parent.child(startIndex - 1).marks)) {
startIndex -= 1;
startPos -= parent.child(startIndex).nodeSize;
}
while (endIndex < parent.childCount && link.isInSet(parent.child(endIndex).marks)) {
endPos += parent.child(endIndex).nodeSize;
endIndex += 1;
}
return { from: startPos, to: endPos };
}