Skip to content

Conversation

@gibson042
Copy link
Member

@gibson042 gibson042 commented Jan 16, 2019

Summary

Builds upon #4277 (diff). This is currently super sloppy, but it works!

Fixes gh-1741

   raw     gz Sizes
277644  82250 dist/jquery.js
 88015  30580 dist/jquery.min.js

   raw     gz Compared to master @ 9cb162f6b62b6d4403060a0f0d2065d3ae96bbcc
 +4001   +996 dist/jquery.js
  +891   +201 dist/jquery.min.js

Size reduction ideas:

Checklist

Copy link
Member

@mgol mgol left a comment

Choose a reason for hiding this comment

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

I've finally went through this PR, nice work! There's some clever code here, it's not that easy to follow! I think I understand most of it now, though. I left comments where I have doubts.

P.S. How do you plan to land it, considering the author of the first commit is different?

// synthetic events by interrupting progress until reinvoked in response to
// *native* events that it fires directly, ensuring that state changes have
// already occurred before other listeners are invoked.
function leverageNative( el, type, forceAdd, allowAsync ) {
Copy link
Member

Choose a reason for hiding this comment

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

This will hurt readability but since forceAdd may be only false or returnTrue, we could squash it with allowAsync, changing the signatures to:

leverageNative( el, type, allowAsync ); // old `leverageNative( el, type, false, allowAsync )`
leverageNative( el, type, false ); // old `leverageNative( el, type, returnTrue )`

That may save some size.

Copy link
Member Author

Choose a reason for hiding this comment

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

So, something like this?

function leverageNative( el, type, allowAsync ) {

	// Missing allowAsync indicates a trigger call, which must force setup through jQuery.event.add
	if ( !allowAsync ) {
		jQuery.event.add( el, type, returnTrue );
		return;
	}

	// Register the controller as a special namespace-universal handler
	dataPriv.set( el, type, false );
	jQuery.event.add( el, type, {} );
}

I think I already tried that, but will specifically look into it.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, I think I meant something like that. If this doesn't help size then consider the request moot.

ns.remove();
} );

QUnit.test( "Check order of focusin/focusout 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.

Has the order changed? Why is this being removed?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I think it now follows native behavior, further cementing my good feelings about #4300 (comment) .

Copy link
Member

Choose a reason for hiding this comment

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

I guess it's fine as we never guaranteed the order and it was different in IE anyway but I'd like to make it clear we're changing it.

@jquery/core what do you think?

Copy link
Member

Choose a reason for hiding this comment

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

If the order changes, this has the potential to break existing code. That kinda smells of a major version to me.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think we've ever documented a guaranteed order, and moreover I don't think we're consistent across supported browsers right now. But I can try restoring this test to see what happens.

Copy link
Member

Choose a reason for hiding this comment

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

Technically speaking it's not a breaking change as we haven't documented the order. That said, if something is consistent between browsers, people tend to start depending on that and changing the behavior may break them. @gibson042 is right the order is different between browsers right now but it's only different between IE & the rest. If a site doesn't support IE (there are more & more of such sites), for their purposes the current order is consistent between browsers. So there's risk involved here.

Copy link
Member

Choose a reason for hiding this comment

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

To add to the above, while the current order is inconsistent between IE & others, what's consistent (& verified by the removed test) is that focusin fires before focus & focusout before blur.

Copy link
Member

@mgol mgol left a comment

Choose a reason for hiding this comment

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

I added a few comments & resolved the discussions where I'm OK with the outcome.

ns.remove();
} );

QUnit.test( "Check order of focusin/focusout 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.

I guess it's fine as we never guaranteed the order and it was different in IE anyway but I'd like to make it clear we're changing it.

@jquery/core what do you think?

@mgol
Copy link
Member

mgol commented Mar 11, 2019

@gibson042 One more thing, a comment that I added in my original PR and I don't see the reply:

How do you plan to land it, considering the author of the first commit is different?

@gibson042
Copy link
Member Author

How do you plan to land it, considering the author of the first commit is different?

Shouldn't be an issue, because eecb078 cherry-picks a commit that we already merged in (but subsequently reverted).

@mgol
Copy link
Member

mgol commented Mar 12, 2019

@gibson042

How do you plan to land it, considering the author of the first commit is different?

Shouldn't be an issue, because eecb078 cherry-picks a commit that we already merged in (but subsequently reverted).

To clarify - do you want to land it as two commits: a re-land of the original one plus your fixes or just squash it to one commit authored by you since the original changes are credited via Git history anyway?

@mgol
Copy link
Member

mgol commented Mar 12, 2019

@gibson042 @timmywil I restored the removed order tests locally and checked in Chrome & Firefox. The order of events is as follows:

  1. focusin
  2. focus
  3. focusin
  4. focusout
  5. blur

When comparing to the orders from #4300, remember #4300 presents focusout/blur on one blurred element & focusin/focus on another focused one; here it's all one input. Therefore, it seems the focusing order is:

  1. focusin
  2. focus
  3. focusin

while the blurring one is:

  1. focusout
  2. blur

Therefore, the order is not native; it's closer to the existing jQuery one but it has one additional second focusin that fails the test. We should look into that before merging IMO as that looks buggy.

@mgol
Copy link
Member

mgol commented Mar 12, 2019

The second focusin is invoked via this[ type ]() in leverageNative. While the event.stopImmediatePropagation() is called, for a focus event that won't prevent focusin from propagating.

An additional complication are the focusin/focusout shims. While focus delegates to focusin & blur to focusout, in non-IE browsers focusin is implemented via focus in capture mode and focusin via blur in capture mode. But even if this shim is disabled the double-focusin issue still exists in the PR currently.

@mgol mgol added the Event label Mar 18, 2019
@mgol mgol added this to the 3.4.0 milestone Mar 18, 2019
@mgol mgol force-pushed the 3.4-native-focus-blur-events branch from 9de7bba to 2846a6b Compare March 20, 2019 14:39
@mgol mgol changed the title [WIP] Event: Leverage native events for focus and blur Event: Leverage native events for focus and blur Mar 20, 2019
@mgol
Copy link
Member

mgol commented Mar 20, 2019

I rebased the PR & restored the focusin/focusout test with one modification: focusin handlers are allowed to fire more than once.

Accept that focusin handlers may fire more than once for now.
@mgol mgol force-pushed the 3.4-native-focus-blur-events branch from 2846a6b to 897f0b0 Compare March 20, 2019 14:41
@mgol
Copy link
Member

mgol commented Mar 20, 2019

The current version of the PR passes tests when run via Karma or by opening /test/?module=event manually but fails when run via TestSwarm. It's not a case of different browser settings as I checked that all on my local TestSwarm install with the same Chrome & Safari browsers. The error happens in the originalEvent type of simulated event event test:

TypeError: undefined is not an object (evaluating 'event.originalEvent.type')
in http://jquery.l//test/unit/event.js on line 2900

It happens in Chrome & Safari, it doesn't happen in Firefox/Edge/IE. It also succeeds in old mobile Chrome/Safari, see my local table (ignore the AJAX failures in IE, that's a BrowserStack issue):
Screen Shot 2019-03-20 at 16 10 25

I'm trying to debug that now...

@mgol
Copy link
Member

mgol commented Mar 20, 2019

OK, it might be a local caching issue, let me try to land it and see on our real TestSwarm instance...

@mgol mgol closed this in 669f720 Mar 20, 2019
gibson042 added a commit to gibson042/jquery that referenced this pull request Mar 22, 2019
mgol pushed a commit that referenced this pull request Mar 25, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Sep 16, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Development

Successfully merging this pull request may close these issues.

focus event ignores additional data when triggered

5 participants