How to move a position range to a different part of the document?

I am trying to implement Sections inside the Canvas. A section should have a title, a due date and it should be possible to rearrange sections using the arrow-up/arrow-down buttons on the gray right panel.

What would be the right way of moving a section up or down? My idea was the following, say I want to move section 5 down:

  1. I first copy all the content from section 5, i.e. the section itself and everything until the next section.
  2. Insert it below section 6.
  3. And then delete the range where section 5 was before.
    private moveSectionDown(sectionNodes: Array<{id: string, pos: number, text: string}>, index: number){
        const sectionToMove = sectionNodes[index];
        const sectionBelow = sectionNodes[index + 1];
        // begining of last section or end of document if section below is the last one.
        const sectionBelowEnd = this.isLastSection(sectionNodes, index + 1) ? this.currentCanvasState.doc.content.size - 1 : sectionNodes[index + 2].pos; 

        const sliceToMove = this.currentCanvasState.doc.cut(sectionToMove.pos, sectionBelow.pos);

        const moveTransaction = this.currentCanvasState.tr.insert(sectionBelowEnd, sliceToMove);
        
        this.dispatchTransactionToCanvas(moveTransaction);

       // after this delete copied section.
    }

var sectionNodes = [
  {"id":"section_hhujde40","text":"section 1","pos":1},
  {"id":"section_bv9sl5j5","text":"section 5","pos":22},
  {"id":"section_rt84rmt6","text":"section 6 ","pos":43}
];

moveSectionDown(sectionNodes, 1);

But this is not working. After the transaction is dispatched the editor remains the same.

I don’t see why the editor would remain the same after inserting content, but your code kind of looks like you expect cut to delete something — it doesn’t, it just isolates the part of the document between the given positions. (Since there’s no transaction involved, it couldn’t possibly change the editor state.)

Hey Marijn, no, I was not expecting cut to actually cut the nodes, I am first trying to make the copying work and then I’ll delete the copied nodes using delete.

I realized this code works depending on the nodes which belong to a section.

I changed the code a little bit:

export interface CanvasSection{
    id: string, 
    text: string, 
    /** The Section's node. */
    node: any;
    startPos: number,
    endPos: number,
    /** All nodes which belong to this section. */
    nodes: any[]
}

private moveSectionDown(sectionNodes: CanvasSection[], index: number){
    const sectionToMove = sectionNodes[index];
    const sectionBelow = sectionNodes[index + 1];

    // slicing nodesToMove to find out when 'insert' stops working.
    const nodesToMove = [sectionToMove.node, ...sectionToMove.nodes].slice(0, 2);
    console.log(JSON.stringify(nodesToMove));

    const moveTransaction = this.currentCanvasState.tr.insert(sectionBelow.endPos, nodesToMove);
    this.dispatchTransactionToCanvas(moveTransaction);

    //TODO: after copying delete copied section.
}

When ‘nodesToMove’ has these 2 nodes ‘insert’ works:

[{
	"type": "section",
	"attrs": {
		"id": "section_veou095v",
		"text": "Section",
		"dueDate": null
	}
}, {
	"type": "text",
	"text": "asd"
}]

When it has this third node ‘insert’ doesn’t work.

[{
	"type": "section",
	"attrs": {
		"id": "section_veou095v",
		"text": "Section",
		"dueDate": null
	}
}, {
	"type": "text",
	"text": "asd"
}, {
	"type": "paragraph",
	"content": [{
		"type": "text",
		"text": "asd"
	}]
}]

I am now trying to find out why.

I think the problem is that you’re putting nodes next to each other (text, paragraph) that your schema doesn’t ever allow to occur in the same parent, so while the replace algorithm will try its best to make content fit, if there’s no way a given fragment will fit, it’ll drop it.

Thanks @marijn, that makes sense. I am going to do a better job modeling my schema and try again implementing sections.