Set the cursor to the click location when editing a text field.

Review Request #13207 — Created Aug. 13, 2023 and submitted

Review Board

Historically, when clicking a text field on a review request to begin
editing, the cursor position would be set to wherever the browser
chooses to set it. That meant if you wanted to edit a specific part of
the text, you had to click twice.

We now preserve the client X/Y coordinates of a mouse click in
InlineEditorView and pass this along to the beginEdit callback. The
subclass for connecting a TextEditorView now passes this along to set
the cursor position.

For CodeMirror, this is fairly straight-forward. We can ask CodeMirror
to convert this into a line number/character offset, and then set that.

For <textarea>s, a different approach is needed.

Browsers sort of have some functionality to help with this, but it's not
perfect. You can set a selection point, which is a single integer
covering a range between 0..length of the text. However, there are two
functions that can now convert a client X and Y coordinate to a
selection point:

  • Document.caretPositionFromPoint: Standard but only on Firefox
  • Document.caretRangeFromPoint: Non-standard but on Chrome, Safari,
    and IE

These are both error-prone in their own ways when used on a <textarea>
(all documented in the code), so to do this correctly, a proxy element
for a <pre> must be created, carefully styled, and then used to get
the caret position.

By implementing these approaches, we now get a very smooth, natural
opening experience, where the user can begin typing exactly where they

Tested on Firefox, Chrome, and Safari.

Tested with some complex documents, with bullet points, wrapping, and
other formatting. In complex documents, as content shifts, the cursor
position may not be on the exact character the user wanted to click,
but it'll always be on the X/Y coordinate.

Set the cursor to the click location when editing a text field.
  1. Ship It!
  1. Ship It!
Review request changed

Status: Closed (submitted)

Change Summary:

Pushed to release-6.x (a40ddc4)