[Editor] Restore cursor positioning after paste/widget-insert#3722
[Editor] Restore cursor positioning after paste/widget-insert#3722jeremywiebe wants to merge 8 commits into
Conversation
…er paste/widget-insert in the markdown editor
…ursor positioning after paste
|
Size Change: -20 B (0%) Total Size: 508 kB 📦 View Changed
ℹ️ View Unchanged
|
npm Snapshot: PublishedGood news!! We've packaged up the latest commit from this PR (8d6a07e) and published it to npm. You Example: pnpm add @khanacademy/perseus@PR3722If you are working in Khan Academy's frontend, you can run the below command. ./dev/tools/bump_perseus_version.ts -t PR3722If you are working in Khan Academy's webapp, you can run the below command. ./dev/tools/bump_perseus_version.js -t PR3722 |
Fixes the cursor positioning issue in the markdown editor after pasting or inserting widgets. The cursor now correctly lands after the content instead of jumping to the end.
| // This command is not implemented. Fall back to setting `value` | ||
| // directly. | ||
| textarea.value = this.props.content; |
There was a problem hiding this comment.
All of our supported browsers support execCommand now, so there's no point in keeping this extra fallback code!
| this.props.onChange( | ||
| { | ||
| content: newContent, | ||
| widgets: { | ||
| ...safeWidgetData, | ||
| ...this.getWidgetsReferencedIn(newContent), | ||
| }, | ||
| }, | ||
| () => { | ||
| const expectedCursorPosition = | ||
| selectionStart + safeText.length; | ||
| Util.textarea.moveCursor(textarea, expectedCursorPosition); | ||
| // After React commits the new content, place the cursor at the end | ||
| // of what we just pasted in. | ||
| this._pendingCursorPos = selectionStart + safeText.length; | ||
| this.props.onChange({ | ||
| content: newContent, | ||
| widgets: { | ||
| ...safeWidgetData, | ||
| ...this.getWidgetsReferencedIn(newContent), | ||
| }, | ||
| ); |
There was a problem hiding this comment.
We are moving to remove the callback prop from onChange. This is currently the only known usage, and we can easily manage it without this legacy prop - plus it doesn't require plumbing the callback value up and down the editor component tree (which we did... and which was broken for a while now!)
| this.props.onChange({ | ||
| content: newContent, | ||
| widgets: newWidgets, | ||
| }); |
There was a problem hiding this comment.
Since we called onChange, the next render should have the same value for the textarea that we just set. I think we could set the cursor position here, and _pendingCursorPos could go away.
There was a problem hiding this comment.
I am pretty sure we have to wait for the next render so that our cursor position refers to the new content string (also, in my testing, even if I set the cursor position no the textarea ref after calling this.props.onChange it jumps to the end of the string after rendering.
Perhaps I'm misunderstanding you.
Co-authored-by: Ben Christel <benchristel@users.noreply.github.com>
Summary:
While working on the Preview NG work, I was going to clean up the two extra parameters in the
onChangecallback prop (silentandcb(aka "callback")). While cleaning up the code I saw that there was some code in the paste path that actually provides a function for thecb.This led me to discover that we'd broken cursor handling when we handle paste in the editor. A while back, we did some cleanup that broke this cursor handling when we stopped passing
silentandcbparameters in higher-level editor components, butEditorwas still sending them - effectively they were dropped on the floor. This results in the cursor always jumping to the end of the content when you paste anywhere.Thsi PR restores this behaviour, but does so entirely within the
Editorcomponent instead of depending on the deprecatedcbonChangeparameter. This allows us to still fully remove thesilentandcbparameters, but restores cursor handling (all within theEditor).Issue: LEMS-4241
Test plan:
Run storybook
Navigate to the Editor Demo page
Add a widget and configure it
Select the widget in the Markdown editor, copy it
Move the cursor to the beginning of the field and type
STARTENDPlace the cursor between
STARTandEND(eg.START|END)Paste
The copied widget should be pasted between
STARTandENDand the cursor should be sitting at the end fo the pasted widget (just beforeEND).