Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pasting should bring you to end of content, not beginning #5317

Closed
melchoyce opened this issue Feb 28, 2018 · 16 comments · Fixed by #13294
Closed

Pasting should bring you to end of content, not beginning #5317

melchoyce opened this issue Feb 28, 2018 · 16 comments · Fixed by #13294
Assignees
Labels
[Feature] Paste [Feature] Writing Flow Block selection, navigation, splitting, merging, deletion... [Status] In Progress Tracking issues with work in progress [Type] Bug An existing feature does not function as intended
Milestone

Comments

@melchoyce
Copy link
Contributor

melchoyce commented Feb 28, 2018

When you paste a couple paragraphs into Gutenberg, your cursor remains at the beginning of the first paragraph you pasted. I expect it to be at the end of the last paragraph pasted.

Example gif:

ezgif com-gif-maker

Related issue:
#6821

@karmatosed
Copy link
Member

Good catch, totally agree it's sensible you'd go to the last place you pasted from.

@jeffpaul jeffpaul added [Type] Enhancement A suggestion for improvement. [Feature] Paste labels Mar 8, 2018
@Kluny
Copy link
Contributor

Kluny commented Mar 12, 2018

I'd like to work on this if no one else is.

@karmatosed
Copy link
Member

That would be awesome @Kluny - thanks!

@mtias mtias added the [Feature] Writing Flow Block selection, navigation, splitting, merging, deletion... label Jul 9, 2018
@designsimply
Copy link
Member

Noting that a similar behavior was reported for inline boundaries at #8387 where pasted content at the end of bold text land the content and caret before the inline boundary instead of at the end where the cursor was at the time of pasting. (26s)

@noisysocks noisysocks added this to the Merge Proposal: Editor milestone Aug 20, 2018
@noisysocks
Copy link
Member

Noticed this during some user testing—it really interrupted the user's flow. Adding this to the Editor milestone as I think it's an important rough edge to smooth off.

@davidwolfpaw
Copy link

I came in to leave this issue, but instead I can second it here.

I submitted a similar issue for the Boostnote editor a few months ago and a fix was created there. Perhaps it could provide a starting point for a solution?

BoostIO/BoostNote-Legacy#1950

@mtias mtias modified the milestones: Merge: Editor, WordPress 5.0 Oct 12, 2018
@earnjam earnjam added [Type] Bug An existing feature does not function as intended and removed [Type] Enhancement A suggestion for improvement. labels Oct 30, 2018
@earnjam
Copy link
Contributor

earnjam commented Oct 30, 2018

Relabeling to bug. I'm not aware of any text field in any software that places the cursor at the beginning of pasted content.

@ellatrix ellatrix self-assigned this Oct 31, 2018
@ellatrix
Copy link
Member

This is something that could be considered when revising the onSplit prop in #10761.

@chrisvanpatten
Copy link
Contributor

It'd be so awesome to see this resolved. I do a lot of copy/paste and this really throws off my flow.

@davewhitley
Copy link
Contributor

Another flow I don't think has been mentioned:

  • Write some text
  • Paste some text at the end of the paragraph
  • Undo with command + z
  • Cursor unexpectedly jumps to the beginning

dec-14-2018 17-03-41

@youknowriad youknowriad removed this from the WordPress 5.0.x Follow Ups milestone Jan 9, 2019
@youknowriad youknowriad added this to the Future: 5.x milestone Jan 9, 2019
@aduth
Copy link
Member

aduth commented Jan 9, 2019

Considering technical implementation, there are a handful of ways which pasted content is handled while within a RichText (paragraph) field. Most relevant to the issue is what happens here:

const shouldReplace = this.props.onReplace && this.isEmpty();
let mode = 'INLINE';
if ( shouldReplace ) {
mode = 'BLOCKS';
} else if ( this.onSplit ) {
mode = 'AUTO';
}
const content = pasteHandler( {
HTML: html,
plainText,
mode,
tagName: this.props.tagName,
canUserUseUnfilteredHTML: this.props.canUserUseUnfilteredHTML,
} );
if ( typeof content === 'string' ) {
const recordToInsert = create( { html: content } );
this.onChange( insert( record, recordToInsert ) );
} else if ( this.onSplit ) {
if ( ! content.length ) {
return;
}
if ( shouldReplace ) {
this.props.onReplace( content );
} else {
this.splitContent( content, { paste: true } );
}
}

There are three routes this can take:

  • If the pasted content can be considered as plaintext (single paragraph text), and the current block is not empty, it's concatenated to the current paragraph. The caret is placed correctly.
  • If the block is not empty, but the content is still plaintext, the paragraph is replaced with a new paragraph. The caret wrongly resets to the beginning of the new paragraph.
  • If the pasted content will result in multiple blocks (multiple paragraphs of text), it will replace if the current block is empty, or split otherwise. The result is effectively the same, the new blocks are added. The caret is wrongly placed at the beginning of the first of the new paragraphs.

A first thought occurs to me: In the second point, why do we replace with a new paragraph? We could just inherit the same behavior as in the first point, and the caret would be placed correctly.

For the last point, whether it's a replacement or a split (which operates by "inserting" blocks), we should consider how to leverage the existing handling for an initialPosition value of block selections to move the caret to the end of the new set of blocks:

// If reversed (e.g. merge via backspace), use the last in the set of
// tabbables.
const isReverse = -1 === initialPosition;
const target = ( isReverse ? last : first )( textInputs );
if ( ! target ) {
this.wrapperNode.focus();
return;
}
target.focus();
// In reverse case, need to explicitly place caret position.
if ( isReverse ) {
placeCaretAtHorizontalEdge( target, true );
placeCaretAtVerticalEdge( target, true );
}

The issue here is whether this is safe to infer:

  • Should it be limited to only when the replacement occurs where the replaced set had included the currently-selected block?
  • Should it be based on the value of the existing updateSelection parameter for insertBlocks?
  • In general, ensuring that we're not overly biased about assuming these actions are triggered as the result of any specific user interactions. It is entirely possible for block inserts and replacements to occur programmatically, including by plugins.

Depending on the answer to these, I could see changes being made either as an effect handler of block replacement and/or in the block selection reducer handling of block insertion.

@ellatrix
Copy link
Member

Reopening as after #13294 the last block will now be selected, but ideally the caret should be put at the end as well.

@gziolo
Copy link
Member

gziolo commented May 23, 2019

Reported also in #15166 by @QiShaoXuan:

When I copy a piece of text into the editor, the cursor always precedes the text, I think it need appear at the end of text.
You can try it in gutenberg website.

@maurisrx:

Yes, I can also confirm that. Every time I copy paste text to new paragraph block, the cursor doesn't automatically move to the end of the text but it stays at the beginning of the text.

@GlennMartin1 :

Same here. Using Chrome on Windows.

@ehti
Copy link

ehti commented Mar 26, 2020

In editor triage today, a related issue came up but we noticed this odd behavior as well.

@adamziel
Copy link
Contributor

Proposed a solution in #21755

@ellatrix
Copy link
Member

ellatrix commented Jun 6, 2020

This was fixed in #21755.

@ellatrix ellatrix closed this as completed Jun 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Paste [Feature] Writing Flow Block selection, navigation, splitting, merging, deletion... [Status] In Progress Tracking issues with work in progress [Type] Bug An existing feature does not function as intended
Projects
None yet