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 or existing plugin to review. Very good chance I am approaching this incorrectly too!
I think calling nodesBetween on the selected range and replacing each text node you find with an uppercased variant (keeping marks per node, so something like schema.text(textNode.text.toUpperCase(), textNode.marks)) would be the most straightforward way to do this.
Possibly better ways to do this, but sharing the following for future users:
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());
}
}
2 Likes