I have a large widget (a long Markdown table, rendered to HTML) which also allows users to edit parts of the underlying source code (individual table cells) using subviews. While moving the cursor across the widget, the main editor (that holds the table widget) will frequently jump to the beginning or the end of the widget itself, instead of just keeping the scroll position where it is. This is likely due to the fact that for a brief moment, the focus lies in the main document and the editor attempts to move either the beginning of the widget range, or the end of it, into view. (Once I type, the editor jumps back to the currently editing table cell.)
Is there a way to prevent this jumping behavior for large widgets programmatically? Ideally something that I can turn on and off with a state effect? Then I could just do some detection on my side and tell the main editor to not jump around in this instance.
Is there a way to prevent the editor “grabbing” focus when the selection changes? The issue is that I want the main (outer) editor to be the source of truth for the data in the table widget. This means that, whenever a user clicks inside a cell to edit it, I set the selection in the outer editor. This then triggers an update in the widget, which then sees that the selection is within a cell, and mounts a sub EditorView inside that cell to allow editing of just that cell. Additionally, all transactions are shared between both views so that the outer editor at all times has perfect knowledge about whatever the user changes inside that table widget.
But for that to work, I need to change the selection in the outer editor, which is when the outer editor will briefly capture focus before the subview is mounted and likewise can grab the focus. As soon as one types in the subview, the editor will scroll to the correct table cell again.
Essentially, I need a way to programmatically set the selection in the outer editor, without it grabbing focus and jumping to different scroll positions. I already suspect that the solution is glaringly obvious and I just can’t see it …
The editor does not grab focus when selection changes. It’ll only mess with the DOM selection on a transaction if it already has focus. Is your inner widget focusable?
first sorry that it took me a month to get back to you. I think I have (almost) solved the issue. I wanted to let you know how; and I also have a couple of follow-up questions if you don’t mind.
First, how I solved it: It turns out that the estimatedHeight and coordsAt methods of the widget are vital for large block widgets. By giving the editor a rough estimated height and returning proper coords for any positions within the widgets I was able to almost completely get the jumping under control.
However, that being said:
The larger the widget (we’re speaking of 100s of rows in a table), the more precise the estimation needs to be. It appears as if Codemirror doesn’t measure the widget’s height precisely after its instantiation, so it appears to use the estimated height, even after the widget has been drawn. Is this intended? If so, is there any way to get access to the View inside the estimatedHeight getter? By temporarily mounting a mock widget, it would be easier to get proper measurements. If not, is this a feature that we could get? Because I have noticed that, the further off the estimate is from the actual rendered widget’s height, the worse the jumping gets — almost unnoticeable for widgets spanning, say, 5 lines, to wild jumps for large tables.
It is not entirely clear what coordinates coordsAt expects. I am currently returning the bounding rect for a table cell if the position is within that cell, but coordinates evokes “x/y”, not a rect?
Lastly, can I improve the documentation of those two functions in such a way as to make it clearer that those two functions are vital for larger block widgets? Might make it more obvious for others who plan on using large widgets.
Drawn content is measured precisely as soon as it appears in the DOM. I don’t think your conclusion here is correct.
As the type shows, you should return a client coordinate rectangle. Those produced by the editor itself tend to be zero-width (cursor positions don’t have a width), but I don’t think returning one with a width is going to cause any issues.
Sure, feel free to open a pull request. But do try to stick to the generally succinct style of the rest of the docs.
Okay, it appeared so to me, apologies! I did feel as if the amount of estimated line height I got influenced the amount of jumping that happens after rendering of the widgets…
I have made a small screen cap to demonstrate the (remaining) problem (in the background I am estimating the height relatively correct with 35px per line which is correct for the setup you can see here): Zettlr Cloud
marijn:
As the type shows, you should return a client coordinate rectangle.
Okay, so it appears to be right as I am using it right now. Thank you.
marijn:
Sure, feel free to open a pull request. But do try to stick to the generally succinct style of the rest of the docs.