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

Fix adding links from the autocompleter #10500

Merged
merged 6 commits into from
Oct 17, 2018

Conversation

talldan
Copy link
Contributor

@talldan talldan commented Oct 11, 2018

Fixes #10496

Description

When adding links from the autocompletion list, the onClickOutside handler on the LinkContainer popover was being triggered, causing the link not to be set and triggering closure of the popover.

This fix adds a clause at the start of the onClickOutside handler, detecting if the click originated from a autocomplete entry and returning early if so.

How has this been tested?

  • Manually tested adding links

Types of changes

Bug fix (non-breaking change which fixes an issue)

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.

@talldan talldan added [Type] Bug An existing feature does not function as intended [Feature] Writing Flow Block selection, navigation, splitting, merging, deletion... labels Oct 11, 2018
@talldan talldan self-assigned this Oct 11, 2018
resetState( event ) {
// URLInput's autocomplete list can trigger onClickOutside on the link container's popover.
// Return early here if the click originated from one of the autocomplete suggestions.
if ( hasIn( event, [ 'target', 'classList' ] ) && includes( event.target.classList, 'editor-url-input__suggestion' ) ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It'd be nice to be able to avoid checking the class here, but I'm short of other ideas beyond having LinkContainer manage a ref to the URLInput's popover.

Copy link
Member

Choose a reason for hiding this comment

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

Yes this is a bit unfortunate.

@ellatrix
Copy link
Member

  1. What commit caused this regression?
  2. Could a test be added to ensure we don't make this regression again?

@talldan
Copy link
Contributor Author

talldan commented Oct 12, 2018

Hi @iseulde - the change was added in the RichText refactor:
https://github.com/WordPress/gutenberg/pull/7890/files#diff-3fc799f44a8120d79cc3867b1d703822R179

Before that, there wasn't an onClickOutside handler and it was a lot harder to dismiss the popover.

I'll have a look at adding a case to the e2e links test.

@talldan talldan force-pushed the fix/adding-link-from-autocomplete-list branch from 61cd065 to 537b18d Compare October 12, 2018 04:40
@ellatrix
Copy link
Member

Why are the link suggestions not in the same popover? That's a bit strange.

@talldan
Copy link
Contributor Author

talldan commented Oct 15, 2018

@iseulde - Not sure, the input is a separate component, and I imagine it's based on other autocomplete implementations. I'll try to think of some other ways to fix this today.

@gziolo gziolo added this to the 4.0 milestone Oct 16, 2018
@talldan talldan force-pushed the fix/adding-link-from-autocomplete-list branch from 537b18d to cd0c1e0 Compare October 16, 2018 13:03
@talldan
Copy link
Contributor Author

talldan commented Oct 16, 2018

Hey @iseulde I've changed the implementation to use a ref now instead of checking class names. I did take a look at if it would be possible to un-nest the suggestions from their popover, but it was a bit too involved.

// so onClickOutside fails to detect that a click on a suggestion occured in the
// LinkContainer. Detect clicks on autocomplete suggestions using a ref here, and
// return early if so.
if ( hasIn( this, [ 'autocompleteRef', 'contains' ] ) && this.autocompleteRef.contains( event.target ) ) {
Copy link
Member

Choose a reason for hiding this comment

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

Why the check?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the user attempted to click outside of the popover when the autocomplete list hadn't been displayed, this.autocompleteRef would be unset. Checking for contains seems to be the safest option.

Copy link
Member

Choose a reason for hiding this comment

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

Using hasIn like this makes me think that this condition is a browser compatibility check for Node.contains(). This isn't necessary since Node.contains() works in all modern browsers.

I think a clearer way to convey what's happening is to simply check for the presence of the ref.

Suggested change
if ( hasIn( this, [ 'autocompleteRef', 'contains' ] ) && this.autocompleteRef.contains( event.target ) ) {
if ( this.autocompleteRef && this.autocompleteRef.contains( event.target ) ) {

@ellatrix
Copy link
Member

Using ref.contains sounds better!

// so onClickOutside fails to detect that a click on a suggestion occured in the
// LinkContainer. Detect clicks on autocomplete suggestions using a ref here, and
// return early if so.
if ( hasIn( this, [ 'autocompleteRef', 'contains' ] ) && this.autocompleteRef.contains( event.target ) ) {
Copy link
Member

Choose a reason for hiding this comment

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

Using hasIn like this makes me think that this condition is a browser compatibility check for Node.contains(). This isn't necessary since Node.contains() works in all modern browsers.

I think a clearer way to convey what's happening is to simply check for the presence of the ref.

Suggested change
if ( hasIn( this, [ 'autocompleteRef', 'contains' ] ) && this.autocompleteRef.contains( event.target ) ) {
if ( this.autocompleteRef && this.autocompleteRef.contains( event.target ) ) {

@@ -96,6 +105,9 @@ class LinkContainer extends Component {
this.onChangeInputValue = this.onChangeInputValue.bind( this );
this.setLinkTarget = this.setLinkTarget.bind( this );
this.resetState = this.resetState.bind( this );
this.bindAutocompleteRef = this.bindAutocompleteRef.bind( this );

this.autocompleteRef = createRef();
Copy link
Member

@noisysocks noisysocks Oct 17, 2018

Choose a reason for hiding this comment

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

It's confusing, I think, to see a mix of createRef() refs and callback refs.

This line here is redundant since bindAutocompleteRef will overwrite this.autocompleteRef when the component is mounted.

The quick way to address this is to delete this line.

Suggested change
this.autocompleteRef = createRef();

A nicer approach, I think, would be to update URLInput to use createRef() refs. Then, LinkEditor can simply override the ref by passing a prop.

class URLInput extends Component {
	constructor( { autocompleteRef } ) {
		super( ...arguments );
		this.autocompleteRef = autocompleteRef || createRef();
	}
	render() {
		...
		return (
			...
			<div
				className="editor-url-input__suggestions"
				...
				ref={ this.autocompleteRef }
			>
			...
		);
	}
}

Copy link
Member

@noisysocks noisysocks left a comment

Choose a reason for hiding this comment

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

Love it! Thanks for adding tests.

@talldan talldan merged commit 16cde93 into master Oct 17, 2018
@talldan talldan deleted the fix/adding-link-from-autocomplete-list branch October 17, 2018 06:36
@talldan
Copy link
Contributor Author

talldan commented Oct 17, 2018

Hey @gziolo - this one is merged now. I think it might be something you wanted cherry-picked into v4.0?

Some of the selectors in the e2e tests have changed since 4.0, so you might get conflicts, this commit should help act as a guideline:
90b08b2

@gziolo
Copy link
Member

gziolo commented Oct 17, 2018

Awesome, thanks @talldan for the heads up and doing the fix. Let's see how the release process goes :)

mcsf pushed a commit that referenced this pull request Nov 1, 2018
* Use a ref to detect clicks in the autocomplete suggestion list

* Add e2e tests to test for regression of link autocomplete issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Writing Flow Block selection, navigation, splitting, merging, deletion... [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unable to insert links when clicking on an autocomplete suggesion
4 participants