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

RichText: don't set selection during selectionchange #13896

Merged
merged 2 commits into from
Feb 15, 2019

Conversation

ellatrix
Copy link
Member

@ellatrix ellatrix commented Feb 15, 2019

Description

Fixes #13895. When the browser updates the selection, we are currently updating the DOM and resetting selection (as we are moving towards RichText becoming a controlled component). Updating the DOM is needed to add the boundary class to formatting elements when the caret moves inside the element. Setting the selection is not really needed, but I thought it'd do no harm.

But... the browser may set the selection differently than we do. E.g. it may set the selection at the end of the text node before the formatting element, where we would set it at the start of the text element inside the formatting element. This causes isRangeEqual to fail (the range is not equal, but visually the same), and we will reset selection during mousedown and mouseup. Selection setting by the browser will be resumed at the selection we set.

The solution is to temporarily remove selection setting until we find a way to prevent it if the selection is at the same text index.

How has this been tested?

Screenshots

Types of changes

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.

@ellatrix ellatrix added this to the 5.1 (Gutenberg) milestone Feb 15, 2019
@ellatrix ellatrix added the [Feature] Rich Text Related to the Rich Text component that allows developers to render a contenteditable label Feb 15, 2019
apply( {
value: record,
current: this.editableRef,
multilineTag: this.multilineTag,
multilineWrapperTags: this.multilineWrapperTags,
prepareEditableTree: this.props.prepareEditableTree,
__unstableDomOnly: domOnly,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part of me wonders if this is the sort of thing where it'd be easier to just pass through whatever additional options verbatim, i.e. ...options from a second object argument. But I can also see the opposite argument of there being value in being explicit, especially in this case where it's something perhaps temporary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I definitely see this as something temporary.

@ellatrix
Copy link
Member Author

I'm not sure if I can make a test case for this. :/

@aduth
Copy link
Member

aduth commented Feb 15, 2019

@iseulde The third GIF in #13895 is keyboard-only and appears like it's resolved by the changes here, in case that could work well as a base for an E2E test case.

@ellatrix
Copy link
Member Author

Ah, it does, thanks!

Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a basic understanding of the underlying issue and the purpose of the selection monitoring in applying the inline boundary highlighting, I think this is a sensible change that works well in my testing. Though I'd agree as well to your further point that we should be able to have more confidence that a selection we'd assign would match a browser behavior.

@ellatrix
Copy link
Member Author

I tried adding the following test, but it passes in puppeteer before this change.

	it( 'should not lose selection direction', async () => {
		await clickBlockAppender();
		await pressKeyWithModifier( 'primary', 'b' );
		await page.keyboard.type( '1' );
		await pressKeyWithModifier( 'primary', 'b' );
		await page.keyboard.type( '23' );
		await page.keyboard.press( 'ArrowLeft' );
		await page.keyboard.down( 'Shift' );
		await page.keyboard.press( 'ArrowLeft' );
		await page.keyboard.press( 'ArrowLeft' );
		await page.keyboard.press( 'ArrowRight' );
		await page.keyboard.press( 'ArrowRight' );
		await page.keyboard.up( 'Shift' );

		// There should be no selection. The following should not do anything.
		await pressKeyWithModifier( 'primary', 'b' );

		expect( await getEditedPostContent() ).toMatchSnapshot();
	} );

@ellatrix
Copy link
Member Author

By passing, I meant that it creates the following, as expected one would expect:

<!-- wp:paragraph -->
<p><strong>1</strong>23</p>
<!-- /wp:paragraph -->

@aduth
Copy link
Member

aduth commented Feb 15, 2019

For me, Cmd+B does nothing in both the case where the selection is correct (this branch) and when incorrect (on master). I'm not sure if that's a bug as well. Maybe the test should type a normal letter instead in the mean time (which would destroy content if the buggy selection behavior exists as on master, and insert a character as in this branch)?

@aduth
Copy link
Member

aduth commented Feb 15, 2019

Example:

it( 'should not lose selection direction', async () => {
	await clickBlockAppender();
	await pressKeyWithModifier( 'primary', 'b' );
	await page.keyboard.type( '1' );
	await pressKeyWithModifier( 'primary', 'b' );
	await page.keyboard.type( '24' );
	await page.keyboard.press( 'ArrowLeft' );
	await page.keyboard.down( 'Shift' );
	await page.keyboard.press( 'ArrowLeft' );
	await page.keyboard.press( 'ArrowLeft' );
	await page.keyboard.press( 'ArrowRight' );
	await page.keyboard.press( 'ArrowRight' );
	await page.keyboard.up( 'Shift' );

	// There should be no selection. The following should insert.
	await page.keyboard.type( '3' );

	expect( await getEditedPostContent() ).toMatchSnapshot();
} );

@ellatrix
Copy link
Member Author

Added an e2e test and everything passes. Confirmed that it fails for master.

@ellatrix ellatrix merged commit 2ce6115 into master Feb 15, 2019
@ellatrix ellatrix deleted the fix/selection-change branch February 15, 2019 16:26
youknowriad pushed a commit that referenced this pull request Mar 6, 2019
* RichText: don't set selection during selectionchange

* Add e2e test
youknowriad pushed a commit that referenced this pull request Mar 6, 2019
* RichText: don't set selection during selectionchange

* Add e2e test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Rich Text Related to the Rich Text component that allows developers to render a contenteditable
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RichText: Non-collapsed selection abruptly interrupted when spanning multiple nodes
2 participants