简体   繁体   中英

ProseMirror - Set caret position to end of selected node

After running command({ href: url }), I would like to deselect current selection and set caret position to end of selected node. NOTE: I am using TipTap

setLinkUrl(command, url) {
command({ href: url })
this.hideLinkMenu()

// Set cursor position after highlighted link
var tag = document.getElementById("editor")

var setpos = document.createRange()

var set = window.getSelection()

const state = this.editor.state

let sel = state.selection
// TODO: Check if sel range > 0
let resolvedPos = state.doc.resolve(sel.from)
let node = resolvedPos.node(resolvedPos.depth)

// This is where I want to set the caret position to the end of the currently selected node
// Currently, I'm using hardcoded indices as proof of concept while the editor contains three paragraph nodes
setpos.setStart(document.getElementById("editor").childNodes[0].childNodes[1], 1)
setpos.setEnd(document.getElementById("editor").childNodes[0].childNodes[1], 1)

setpos.collapse(true)

set.removeAllRanges()

set.addRange(setpos)

tag.focus()

This is how you'd do it with ProseMirror, I guess it should translate to TipTap too.

A selection can span multiple nodes so we're going to move the caret the the end of the end of the last selected node.

The resolved position of the end of the selection is at selection.$to . It's a convention in ProseMirror that resolved positions start with a $ .

To find the next "cut" at the end of the current node of a resolved position you can use the after() method. This will return a position after the node ends so we need to subtract one from it.

Finally, we need to create a new selection and apply it by dispatching a document transformation using the setSelection() method. Remember that TextSelection needs a resolved position to be instantiated not a position number.

If we put it all together we can create a command to do this:

import {TextSelection} from "prosemirror-state";

function moveToEnd (state, dispatch, view) {
    // Don't dispatch this command if the selection is empty
    if (state.selection.empty) return false;

    // Subtract one so that it falls within the current node
    const endPos = state.selection.$to.after() - 1;
    const selection = new TextSelection(state.doc.resolve(endPos));
    let transaction = state.tr.setSelection(selection);

    if (dispatch) dispatch(transaction.scrollIntoView());

    return true;
}

You can use this command with the keymap module when instantiating the editor:

keymap({
    'Mod-Shift-j': moveToEnd
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM