🌐 AI搜索 & 代理 主页
Skip to content

Conversation

@caillou
Copy link
Contributor

@caillou caillou commented Jun 13, 2017

Summary

This PR ensures that event.stopPropagation() is respected for event handlers that were registered using the native element.addEventlistener() method when the event was triggered by jQuery's .trigger('click') method.

This PR fixes #3693.

The ticket was closed at first with the following argument:

jQuery has never been able to guarantee full interoperability of native-vs-jQuery event handlers.

Nonetheless, the discussion lead me to believe, that this incompatibility between native and jQuery event handling could be fixed and that such a fix is worthwhile.

Checklist

caillou added 2 commits June 13, 2017 18:22
This test reproduces the following bug reported in jquery#3693:

Calling `.click()` triggers event-handler that was natively
registered event if `e.stopPropagation()` is called on the parent.
Copy link
Member

@dmethvin dmethvin left a comment

Choose a reason for hiding this comment

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

@caillou this looks like it might work! Can you fix the typo and review the situation I mentioned to see if we might need another test case?


var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;
var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
stopPropagationCallback = function( e ) {
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we should have this inside trigger() since it is only used there. Opinions welcome.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The difference is the following:

  • If we define the function within the trigger method, it is defined every time trigger is called.
  • If we define the function within the AMD callback function as I did here, the function will be defined only once, but even if the trigger method is never used. Additionally, there is an additional scope lookup.

All in all, these considerations are micro optimisations, that are not really worth considering. The questions is more one of culture within a project. We could also define it at the end of the file, just before the return jQuery statement.

I will look at the other files and see how it is usually handled within the jQuery project.

jQuery.event.triggered = type;

if ( event.isPropagationStopped() ) {
lastElement.addEventListener( type, stopPropagationCallback );
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be possible to get here with lastElement === undefined if the incoming event already had propagation stopped? Maybe initialize with lastElement = elem?

Copy link
Member

Choose a reason for hiding this comment

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

Hmmm, this does bring up the problem of .stopImmediatePropagation() which isn't fixed. Since that method is sensitive to the order that handlers are attached and ours is always going to be last, there isn't much we can do for that 🤷‍♂️ .

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dmethvin One option with the .stopImmediatePropagation() would be to register an additional event handler on the second to last element (the great ancestor) if there is one present, that stops the propagation.

But this seems rather fiddly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dmethvin I will try to add a test-case for the lastElement === undefined case. But I don't yes see how this could happen. How can the propagation of the incoming even already be stopped?

$anchor2[ 0 ].removeEventListener( "click", neverCallMe );
} );

QUnit.test( "triggerd events stopPropagation() for natively-bound events", function( assert ) {
Copy link
Member

Choose a reason for hiding this comment

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

triggered

Copy link
Member

@gibson042 gibson042 left a comment

Choose a reason for hiding this comment

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

I had my doubts, but this looks good. 👍

i = 0;
while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {

lastElement = cur;
Copy link
Member

Choose a reason for hiding this comment

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

You can reduce the size increase of jquery.min.gz by using eventPath[ i - 2 ] below rather than introducing a new variable.

Copy link
Contributor Author

@caillou caillou Jun 20, 2017

Choose a reason for hiding this comment

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

@gibson042 in my opinion, it would reduce the size at a high cost of code readability. What is the code guideline in the jQuery project with regard to readability v.s. size?

It was my initial thought too. But I felt that the eventPath.pop() on line 126 makes it fairly difficult to follow the code.

Copy link
Member

@dmethvin dmethvin left a comment

Choose a reason for hiding this comment

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

Thanks for your PR @caillou !

@caillou
Copy link
Contributor Author

caillou commented Jun 20, 2017

@dmethvin @gibson042: I have added a test with a perviously stopped event and fixed it.

Could you review this again? Sorry for the trouble, I should have thought about this.

This yields the question: Do we really want to go forward with this PR? While it helps with interoperability between native and jQuery events, I wonder if it is worth the trouble. WDYT?

@timmywil timmywil added this to the 3.3.0 milestone Jun 26, 2017
@dmethvin
Copy link
Member

@caillou I think you have a pretty small patch here and it could be useful. What are your concerns?

@caillou
Copy link
Contributor Author

caillou commented Jun 26, 2017

@dmethvin Good. No real concerns. What is the workflow? Do I need to do anything, or will it get merged at some point?

@dmethvin
Copy link
Member

@caillou Yes, we'll merge it shortly. Thanks!

@timmywil timmywil closed this in 490db83 Jul 10, 2017
@lock lock bot locked as resolved and limited conversation to collaborators Jan 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Development

Successfully merging this pull request may close these issues.

jQuery does not stop propagation of jQuery.click() on native event-handlers

4 participants