Codemirror: Unexpected scroll position after setValue twice and calling scrollIntoView

Created on 13 Mar 2013  路  3Comments  路  Source: codemirror/CodeMirror

At CodeMirror: f936a70

I'm seeing an issue where if I set the value of an editor twice and call scrollIntoView I'm not getting the scroll position as I would expect it.

Reduction:

<style>.CodeMirror { height: 5em; } /* 5 lines tall */</style>
<button id="button">Change text and reveal line</button>
<textarea id="code"></textarea>

<script>
// Create editor.
var textarea = document.getElementById('code');
var cm = CodeMirror.fromTextArea(textarea, {lineNumbers: true, lineWrapping:true});
// Create 300 lines.
for (var i=0, lines=[]; i<300; ++i) lines.push(i);
// Set the lines and scroll into view line 251.
document.getElementById('button').addEventListener('click', function() {
    cm.setValue("abc");
    cm.setValue(lines.join("\n"));
    cm.setSelection({line: 250, ch:0}, {line: 250});
    cm.scrollIntoView({line: 250, ch:0});
});
</script>

After clicking the button twice the editor is at line 1:

Screen Shot 2013-03-12 at 5 56 42 PM

First time clicking the button correctly scrolls to line 251. The second time however it scrolls to line 1. It continues to alternate on future clicks between line 251 and line 1. I would always expect the result to be line 251. Note the selection is still correct even though the line is not visible.

Most helpful comment

Related discussion thread how to set view stay in current position when cm.doc.setValue().

FWIW, this is how I managed to call setValue and not have any scroll modifications:

  // Set the value, but do not scroll to the top.
  var scrollInfo = this.codeMirror.getScrollInfo();
  this.codeMirror.setValue(value);
  this.codeMirror.scrollTo(scrollInfo.left, scrollInfo.top);

I wish there were an options object to setValue, similarly to setSelection, so one could say:

this.codeMirror.setValue(value, {scroll: false});

All 3 comments

Is it expected that we should call refresh somewhere? If we're in an operation, then a refresh doesn't seem to do anything and the scrollIntoView never works. For example replacing the click handler with:

// Set the lines and scroll into view line 251.
document.getElementById('button').addEventListener('click', function() {
    cm.setValue("abc");
    cm.operation(function() {
        cm.setValue(lines.join("\n"));
        cm.refresh();
        cm.setSelection({line: 250, ch:0}, {line: 250});
        cm.scrollIntoView({line: 250, ch:0});
    });
});

Thanks for the minimal reproduction case. Problem was that CodeMirror relied on the asynchronous 'scroll' event to update its understanding of its current scroll position. In sync code like the one you had, it would believe that it was still at the right position when scrollIntoView was called, and not update.

Related discussion thread how to set view stay in current position when cm.doc.setValue().

FWIW, this is how I managed to call setValue and not have any scroll modifications:

  // Set the value, but do not scroll to the top.
  var scrollInfo = this.codeMirror.getScrollInfo();
  this.codeMirror.setValue(value);
  this.codeMirror.scrollTo(scrollInfo.left, scrollInfo.top);

I wish there were an options object to setValue, similarly to setSelection, so one could say:

this.codeMirror.setValue(value, {scroll: false});
Was this page helpful?
0 / 5 - 0 ratings

Related issues

ellisonbg picture ellisonbg  路  4Comments

alangdm picture alangdm  路  3Comments

niftylettuce picture niftylettuce  路  4Comments

misterbeebee picture misterbeebee  路  4Comments

blgm picture blgm  路  4Comments