I’m trying to implement a command to shift nodes up and down. Figured I’d just do a .delete() then an .insert(). I have the relative index that I want to shift by (-1, -2, 1, 2, etc.), and the index of the current node (from selection.$head.index(0)) but I can’t figure out how to go from currentIndex + relativeIndex to a position for the .insert() command.
I was looking for something like Node.maybeChild() that would return additional info about the node like its offset into the parent.
Sounds like you either need to do some Position Mapping between the delete() and insert() or you need to complete the move in a single ReplaceAroundStep.
The ReplaceAroundStep is a bit more complex to set up properly, but it works cleanly as a single operation.
Position Mapping is also an important skill when creating a sequence of editing actions. I avoided partial-mapping of positions for a long time but after embracing it, it has made my util methods much more composable/reusable.
ResolvedPos methods, such as before and after, might help. You may also need to retrieve the next sibling (using index/indexAfter) and add/subtract its size.
I don’t think you can.
You will need a ResolvedPos which you can not get from an index.
Nodes don’t have a positions. They have sizes though which you can use to calculate the positions you need.
Bellow is a function I use to get the boundaries of a mark. (may not be the correct way I am new here )
The ResolvedPos would come from your selection ($cursor in my case).
This line let from = ResolvedPos.start() + ResolvedPos.parentOffset - ResolvedPos.textOffset;
export function getMarkRange(ResolvedPos, mark) {
// console.log('ResolvedPos.parentOffset');
// console.log(ResolvedPos.parentOffset);
//
// console.log('ResolvedPos.textOffset');
// console.log(ResolvedPos.textOffset);
//
// console.log('ResolvedPos.start()');
// console.log(ResolvedPos.start());
//
// console.log('ResolvedPos.end()');
// console.log(ResolvedPos.end());
//
// console.log('ResolvedPos.before()');
// console.log(ResolvedPos.before());
//
// console.log('ResolvedPos.after()');
// console.log(ResolvedPos.after());
// ResolvedPos.parent.childAfter(ResolvedPos.parentOffset)
let parent = ResolvedPos.parent;
let index = ResolvedPos.index();
// ResolvedPos is at the end of parent there are nodes with this index
if (parent.content.content.length === index){
return false;
}
const child = parent.content.content[index];
let from = ResolvedPos.start() + ResolvedPos.parentOffset - ResolvedPos.textOffset;
let to = from + child.nodeSize;
// look ahead
for (let i = index + 1; i < parent.content.content.length; i++) {
let temp = parent.content.content[i];
if(mark.isInSet(temp.marks)){
to += temp.nodeSize;
}else{
break;
}
}
// look back
for (let i = index - 1; i >= 0 ; i--) {
let temp = parent.content.content[i];
if(mark.isInSet(temp.marks)){
from -= temp.nodeSize;
}else{
break;
}
}
return { from, to };
}
@marijn Maybe consider add a Node API that can return the node absolute pos, the parameter is doc and the node? Perhaps the immutable data structure make it difficult?
A given node instance may appear in a document multiple times, hence node object identity is absolutely useless for referring to a specific node in a document.
If you already know the parent node and the index, it seems like a ResolvedPos isn’t going to add a lot of information. Also, you’d get a resolved position rooted in a local node instead of the document, which is likely to be confusing. Maybe a method to go from an index to a node-local offset would be more useful?
In your use case, do you have a resolved position that goes through the node? Would a posAtIndex(depth, index) method on ResolvedPos cover what you need?
I do have a ResolvedPos, but it doesn’t go through the node I have the index for. (But I don’t think that would matter for your suggestion?)
In the two cases that I need this I have a either a shortcut or UI triggered command which moves the selection backward or forward some number of nodes. In one case it’s a constant amount between 1-3, in another it involves starting at the current node and searching forward or backward for the next node of interest. So I have the ResolvedPos of the cursor, and I take position.index(x) + indexOffset to get the index of the node to move the cursor to.