Breaking changes in recent versions of jQuery - focus handling
antranig.basman at colorado.edu
Fri Dec 20 01:13:08 UTC 2013
Continuing with my FLUID-5185 work upgrading our core framework dependency, I can report on some more issues
which we need to be aware of working with current versions of jQuery, and other bugs. It seems that we have
good consensus on our approach to $.browser, which I have now implemented (thanks, Colin). Note that
"FluidDocument.js" is now a required dependency for every Infusion page using the framework - it should
appear immediately after Fluid.js.
A crucial change in newer jQueries (most likely post 1.9) relates to propagation of focus events. In fact,
this change sheds light on some oddities that we noticed over the past 5 years but never investigated
completely - these led me, for example, to insert a new jqUnit.simulateFocus method into my IE compatibility
pull request which can be seen here:
(this pull request is independent of and predates the jQuery upgrade work).
It seems that the jQuery change directly impacts this area - the fidelity of relay in synthesised focus and
blur events. It appears that historically, jQuery has relayed these events "synthetically" - that is, with a
direct relay within the jQuery event system between firers and listeners. The change is that these events
are now relayed "natively" - that is, jQuery makes no extra attempt beyond what the browser does to relay
the event - a trigger of "focus" relays to a native "focus" which the browser may or may not then relay to a
listener attached to "focus". You can currently investigate the old behaviour, for example, by browsing to
and setting a breakpoint in the onBlur handler - HTML5UploaderSupport.js line 271 - if you look down the
stack, you will see that we are directly connected to the site of the "blur" call in the test case, "
inputs.eq(1).blur();" at line 308. In the new jQuery this will no longer be the case - if we reach this
site, the browser's event engine will be at the base of the stack.
Whilst these changes are in theory helpful, they are in general very disruptive to our test cases which have
been written with various assumptions which are now no longer valid. In particular there are two important
kinds of change to be aware of:
i) focus and blur events for DOM nodes which are not visible are now in general not relayed. This implies
that display: none needs to be taken off the remainder of our markup fixtures (this has been generally been
being removed in any case)
ii) focus and blur events in general now may well not be relayed synchronously between firers and listeners
- since these now pass through the browser's event dispatching engine. Thankfully in the meantime we have
now acquired the "IoC Testing framework" which allows us to rewrite some of these tests in a way which
abstracts over the presence or absence of asynchrony, without which we would be in a nasty "callback hell".
In addition to these points, the exposure of "native focus relay" has itself exposed a clear browser bug, in
Firefox's handling of focus events on file upload controls. It appears that a "blur" for this kind of
control is never honoured by Firefox at all. Previously, jQuery would paper over this issue for us as a
result of its "direct framework relay" of the blur event, making us believe it had been honoured. I've
uploaded a very minimal test case for this issue here:
This should be reported upstream to Mozilla in due course.
In the meantime, the workaround is to produce a dummy control onto which we transfer focus when a "blur" is
required on the primary control. Firefox is able to service a "blur" when focus is pushed onto this element,
even if it can't service a "blur" directly. In order to write the test cases reliably, I've also had to
expose a dedicated "focus" event from the browse control, without which it is impossible to sequence the
tests properly - we may find ourselves doing this in a lot of components as we write a11y tests for them.
The remaining "unexpected failures" are in InlineEdit which I will look at this evening, and I expect the
causes to be quite similar - if they are not, I'll write a further report.
In general, the take-home message is captured in points i) and ii) above - i) don't expect focus tests to
work any more on markup which is not visible, and further, keyboard-a11y-tests.js has been added to the
existing collection of tests which will not run correctly if the browser window is not top level (since
native focus events will not be delivered in that case either), and ii) be prepared to write focus-aware
tests using the IoC testing framework, and to expose additional events from these components to let these
tests be sequenced properly. Here's a sample in my rewrite of one of the HTML5 Uploader support tests:
Sorry for another long posting, but simulation of focus in our tests is a crucial area where we require
reliability as an a11y community, and this upgrade of one of our core framework dependencies has forced some
of these portability annoyances into visibility.
More information about the fluid-work