Search code examples
prose-mirror

How to replace currently selected content in ProseMirror


A little lost in ProseMirror at the moment and trying to understand the correct way to replace the text of the current selection. I want to be able to toggle the case between lower/upper case.

state.selection.content(); will return slice of the relevant nodes under the selection, and the content that is selected, but does not return the range within each node that would need to replaced.

I assume I would need to create a new text node to replace the range within each selected node something like:

const updatedText = node.textContent.toUpperCase();
const textNode = state.schema.text(updatedText);
transaction = transaction.replaceWith(startPos, startPos + node.nodeSize, textNode);

How do I get the range to replace within each node?

Unfortunately, I cannot find a suitable example.


Solution

  • Ended up with the following that uses replaceWith.

    May be a better solution, but hopefully this helps others.

    See comments inline:

    const execute = (casing, state, dispatch) => {
      // grab the current transaction and selection
      let tr = state.tr;
      const selection = tr.selection;
    
      // check we will actually need a to dispatch transaction
      let shouldUpdate = false;
    
      state.doc.nodesBetween(selection.from, selection.to, (node, position) => {
        // we only processing text, must be a selection
        if (!node.isTextblock || selection.from === selection.to) return;
    
        // calculate the section to replace
        const startPosition = Math.max(position + 1, selection.from);
        const endPosition = Math.min(position + node.nodeSize, selection.to);
    
        // grab the content
        const substringFrom = Math.max(0, selection.from - position - 1);
        const substringTo = Math.max(0, selection.to - position - 1);
        const updatedText = node.textContent.substring(substringFrom, substringTo);
    
        // set the casing
        const textNode = (casing === 'uppercase')
          ? state.schema.text(updatedText.toUpperCase(), node.marks)
          : state.schema.text(updatedText.toLocaleLowerCase(), node.marks);
    
        // replace
        tr = tr.replaceWith(startPosition, endPosition, textNode);
        shouldUpdate = true;
      });
    
      if (dispatch && shouldUpdate) {
        dispatch(tr.scrollIntoView());
      }
    }