-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Make sure autocompleted values make it into the block's saved content #7486
Conversation
This is the first time I've looked at this code, so I'm suggesting this as a potential approach. If it's acceptable, I'll write tests :) |
components/autocomplete/index.js
Outdated
@@ -243,6 +243,9 @@ export class Autocomplete extends Component { | |||
range.setStartAfter( child ); | |||
} | |||
range.deleteContents(); | |||
if ( undefined !== this.props.onChange ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we default to noop
instead? Can we update docs to reflect this new change introduced?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me, at this point I just want confirmation that this is the right type of fix, and I'll add a default noop and write tests if it is :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @notnownikki, thanks for working on this! I was thinking I'd need to look into this issue this morning, and it was a pleasant surprise to see you already had.
I'm thinking it might be better if we manually dispatch an input
event on the contenteditable element since we already listen for an input
event and it represents what is occurring and wouldn't require any interface change.
Maybe something like this at the end of insertCompletion
:
// IE11 doesn't provide an InputEvent constructor.
const inputEvent = typeof InputEvent !== 'undefined' ? new InputEvent() : (() => {
const e = document.createEvent( 'UIEvent' );
e.initEvent( 'input', true /* bubbles */, false /* cancelable */ );
return e;
})();
range.commonAncestorContainer.closest( '[contenteditable=true]' ).dispatch( inputEvent );
What do you think?
7cd34bd
to
76193e4
Compare
@brandonpayton that's a much cleaner solution! I've pushed up a new change that dispatches in input event, and it all seems to work fine :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fix looks good to me, though at the moment my IE11 virtual machine is not cooperating.
inputEvent = document.createEvent( 'UIEvent' ); | ||
inputEvent.initEvent( 'input', true /* bubbles */, false /* cancelable */ ); | ||
} | ||
range.commonAncestorContainer.closest( '[contenteditable=true]' ).dispatchEvent( inputEvent ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be strict, the polyfill for Element#closest
should be imported at the top of this module:
Line 4 in 5a57e6f
import 'element-closest'; |
inputEvent = new window.InputEvent( 'input', { bubbles: true, cancelable: false } ); | ||
} else { | ||
// IE11 doesn't provide an InputEvent constructor. | ||
inputEvent = document.createEvent( 'UIEvent' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honest question: what makes UIEvent
more apt than Event
? Can we document that choice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was following @brandonpayton's lead on this... but looking at it, for consistency, shouldn't it be an InputEvent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps. :) Since this is an IE quirk, I don't know. I brought up Event
because the typical examples out there on how to "deal with IE" use it instead of other event types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, InputEvent
is not supported at all, even with the fallback interface. It has to be either Event
or UIEvent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we would be fine using Event
, but my reason is that the InputEvent
interface is based on UIEvent
in the spec:
https://w3c.github.io/uievents/#idl-inputevent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel strongly enough about the Event
/UIEvent
choice and don't mean to block this PR — so, if this PR also correctly fixes the problem in IE11, feel free to merge it!
Tested in IE11, works fine! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested in IE11, and the fix is effective to address #7444. However, I am seeing our manually dispatched input
event trigger another display of the completion menu. This also occurs in Firefox.
If I hackinsertCompletion
to insert a space after a completion, the menu is not shown after the completion is inserted. This makes some sense as the originally inserted text would indeed trigger the completer menu if it was input by the user.
Once the autocomplete token PR #6577 is merged (hopefully later today), this will no longer occur because the cursor is placed outside completion tokens after insertion.
I am happy with this change but think we should wait to merge after #6577.
@brandonpayton thanks! I'm happy to wait :) |
@brandonpayton - should we still wait for #6577? |
@gziolo, I don't want to wait, but there is a bug with this solution if we do not have separation because the input event triggers A temporary workaround might be to insert a non-breaking zero-width space following a completion. That would avoid this issue. It might introduce a surprising stop when moving the cursor with arrow keys, but that seems more tolerable than this bug. What do you think? |
2a83753
to
86e6638
Compare
Yes, works for me. I can see the user handle properly published 🎉 |
Description
Potential fix for #7444
When an autocompleter does an insert-at-caret, the block isn't notified of the change,
and so the content doesn't get updated unless the user carries on typing.
This change dispatches an input event, which the editable component listens for and updates the block's attributes.
How has this been tested?
Carry out the steps shown in #7444
and the username should be saved correctly.
Types of changes
Bug fix
Checklist: