scniro / react-codemirror2

Codemirror integrated components for React
MIT License
1.65k stars 192 forks source link

onBeforeChange returns wrong third parameter when previous change is canceled #279

Open simpsonphile opened 2 years ago

simpsonphile commented 2 years ago

My intention is to block some lines from the edition. When I try to edit code specified in linesReadOnly it works fine but when the next action is correct for example some changes in line 10 then nValue returns the wrong string (with changes that were blocked by changeObj.cancel()

const linesReadOnly = [0,1,2,3];
const onBeforeChange ({}, changeObj, nValue: string) => {
          if (~linesReadOnly.indexOf(changeObj.from.line)) {
            changeObj.cancel();
          } else {
            setValue(nValue);
          }
        }
Sruli-RD commented 2 years ago

Hey, just had the same issue. Whipped up a solution if you're still having this issue. For reference, cm is the first value that is passed in from onBeforeChange which you are destructuring to an empty object.

// onBeforeChange will get triggered again with the origin of "setValue".
// This prevents an infinite loop
if (action.origin !== "setValue") {
    // Getting the first selection in the array (If you are dealing with multiple cursors you would want to get all the ranges)
    const oldSelection = cm.doc.sel.ranges[0];
    // Getting the old scroll info from CodeMirror
    const scrollInfo = cm.getScrollInfo();
    const oldScrollTop = scrollInfo.top;
    const oldScrollLeft = scrollInfo.left;
    // Setting the data back to your old value
    cm.setValue(INSERT_OLD_CODE_VALUE_HERE);
    // Setting the old selections in place (If you are dealing with multiple cursors you would want to use cm.setSelections and 
    pass them all in)
    cm.setSelection(oldSelection.anchor, oldSelection.head);
    // Scrolling back to where we were
    cm.scrollTo(oldScrollLeft, oldScrollTop);
}