Bug 179990

Summary: Phantom focus/blur events fire on clicking between text input fields when listening with addEventListener
Product: WebKit Reporter: Chris Lienert <rez>
Component: UI EventsAssignee: Ryosuke Niwa <rniwa>
Status: RESOLVED FIXED    
Severity: Normal CC: bdakin, bolusmjak, cdumez, dbates, d.kislenko, fellaslimspam, rniwa, thorton, webkit-bug-importer, wenson_hsieh
Priority: P2 Keywords: InRadar
Version: Safari 11   
Hardware: Mac   
OS: macOS 10.13   
Attachments:
Description Flags
Fixes the bug thorton: review+

Chris Lienert
Reported 2017-11-23 19:30:18 PST
With two or more text inputs on a form, switching focus by click from one to another sometimes causes an extra focus/blur to fire. Steps to reproduce Start with a form with two or more text inputs and watch focus/blur events. Demo: https://codepen.io/cliener/pen/ooGpwW 1. Click on one of the text inputs (#1) 2. Click on another text input (#2) 3. Repeat the above until extra focus/blur events show. The phantom events only seem to fire on the second and subsequent text inputs. Expected behaviour Each clicked focus shift should fire single blur/focus events. Element #1 blur Element #2 focus Element #2 click Actual behaviour Some clicked focus shifts fire secondary blur/focus events with the net effect of: Element #1 blur Element #2 focus Element #1 blur Element #2 focus Element #2 click Additional notes Monitoring the events in the console with monitorEvents() does not show the phantom events. The extra events only appear to be visible when listening to the DOM focus/blur events with addEventListener. Disabling "Look up & data detectors" (System Preferences: Trackpad: Point & Click: Look up & data detectors) fixes the bug. Tested and recreated in: - Safari Version 11.0.1 (13604.3.5) on MacOS 10.13.1 (17B48) - Safari Technology Preview Release 44 (Safari 11.1, WebKit 13605.1.13.2) Impact of this bug Custom form elements which depend on focus/blur can get stuck in a loop as demonstrated in React Datepicker https://github.com/Hacker0x01/react-datepicker/issues/1077 This bug has also been noted in React where we're trying to find a workaround https://github.com/facebook/react/issues/10871
Attachments
Fixes the bug (7.17 KB, patch)
2018-11-21 18:37 PST, Ryosuke Niwa
thorton: review+
Radar WebKit Bug Importer
Comment 1 2017-11-24 22:53:58 PST
Ryosuke Niwa
Comment 2 2018-11-20 17:11:54 PST
Hm... I can't reproduce this on 12.0.1 or STP70.
Ryosuke Niwa
Comment 3 2018-11-20 17:29:34 PST
Can't reproduce on Safari 11.1 (13605.1.33.1.4) either.
Ryosuke Niwa
Comment 4 2018-11-20 17:46:14 PST
Oh, that's because I always disable force click. I can reproduce reliably now.
Ryosuke Niwa
Comment 5 2018-11-20 19:41:13 PST
The issue here is that TemporarySelectionChange which is created by TextIndicator::createWithRange is setting & restoring the selection, which also sets & restores the focus. I'd have to talk with Beth / Tim to figure out what we ought to do instead.
Tim Horton
Comment 6 2018-11-20 23:06:05 PST
(In reply to Ryosuke Niwa from comment #5) > The issue here is that TemporarySelectionChange which is created by > TextIndicator::createWithRange is setting & restoring the selection, which > also sets & restores the focus. I'd have to talk with Beth / Tim to figure > out what we ought to do instead. To get rid of that selection change, we'd need all of the paint-selection-only painting code to take an arbitrary range instead of always looking at the selection. I think that would be pretty nontrivial. Instead ideally we'd just stop the events from propagating, I think?
Ryosuke Niwa
Comment 7 2018-11-20 23:12:22 PST
(In reply to Tim Horton from comment #6) > (In reply to Ryosuke Niwa from comment #5) > > The issue here is that TemporarySelectionChange which is created by > > TextIndicator::createWithRange is setting & restoring the selection, which > > also sets & restores the focus. I'd have to talk with Beth / Tim to figure > > out what we ought to do instead. > > To get rid of that selection change, we'd need all of the > paint-selection-only painting code to take an arbitrary range instead of > always looking at the selection. I think that would be pretty nontrivial. > > Instead ideally we'd just stop the events from propagating, I think? We can just avoid firing of selection related events & avoid changing that focus. Would moving the focus important here? If not, FrameSelection::setSelection takes an option to not set focus.
Tim Horton
Comment 8 2018-11-20 23:18:40 PST
(In reply to Ryosuke Niwa from comment #7) > (In reply to Tim Horton from comment #6) > > (In reply to Ryosuke Niwa from comment #5) > > > The issue here is that TemporarySelectionChange which is created by > > > TextIndicator::createWithRange is setting & restoring the selection, which > > > also sets & restores the focus. I'd have to talk with Beth / Tim to figure > > > out what we ought to do instead. > > > > To get rid of that selection change, we'd need all of the > > paint-selection-only painting code to take an arbitrary range instead of > > always looking at the selection. I think that would be pretty nontrivial. > > > > Instead ideally we'd just stop the events from propagating, I think? > > We can just avoid firing of selection related events & avoid changing that > focus. Would moving the focus important here? If not, > FrameSelection::setSelection takes an option to not set focus. No, I don't think moving the focus is important.
Ryosuke Niwa
Comment 9 2018-11-21 18:37:23 PST
Created attachment 355449 [details] Fixes the bug
Tim Horton
Comment 10 2018-11-21 19:14:42 PST
Comment on attachment 355449 [details] Fixes the bug View in context: https://bugs.webkit.org/attachment.cgi?id=355449&action=review > Source/WebCore/editing/Editor.h:107 > + DoNotSetFcous = 1 << 1, Typo "Fcous".
Tim Horton
Comment 11 2018-11-21 19:16:02 PST
Comment on attachment 355449 [details] Fixes the bug View in context: https://bugs.webkit.org/attachment.cgi?id=355449&action=review > Source/WebCore/ChangeLog:15 > + Unfortunately, no new tests since force click testing is broken :( See <rdar://problem/31301721>. There are other ways to generate textindicators, though (find-in-page, lookup, some kinds of drags; see TextIndicator::createWithSelection...). You might be able to get one of them to work.
Ryosuke Niwa
Comment 12 2018-11-21 22:26:10 PST
(In reply to Tim Horton from comment #11) > Comment on attachment 355449 [details] > Fixes the bug > > View in context: > https://bugs.webkit.org/attachment.cgi?id=355449&action=review > > > Source/WebCore/ChangeLog:15 > > + Unfortunately, no new tests since force click testing is broken :( See <rdar://problem/31301721>. > > There are other ways to generate textindicators, though (find-in-page, > lookup, some kinds of drags; see TextIndicator::createWithSelection...). You > might be able to get one of them to work. But those either move the focus first or don't move the focus.
Ryosuke Niwa
Comment 13 2018-11-21 22:38:14 PST
(In reply to Tim Horton from comment #10) > Comment on attachment 355449 [details] > Fixes the bug > > View in context: > https://bugs.webkit.org/attachment.cgi?id=355449&action=review > > > Source/WebCore/editing/Editor.h:107 > > + DoNotSetFcous = 1 << 1, > > Typo "Fcous". Fixed. Thanks for the review!
Ryosuke Niwa
Comment 14 2018-11-21 22:39:17 PST
Daniel Bates
Comment 15 2018-11-21 23:11:51 PST
Comment on attachment 355449 [details] Fixes the bug View in context: https://bugs.webkit.org/attachment.cgi?id=355449&action=review > Source/WebCore/editing/Editor.cpp:209 > + if (options & TemporarySelectionOption::EnableAppearanceUpdates) We should make option an OptionSet. > Source/WebCore/editing/Editor.cpp:227 > + if (m_options & TemporarySelectionOption::IgnoreSelectionChanges) { We should make m_option an OptionSet.
Ryosuke Niwa
Comment 16 2018-11-21 23:42:27 PST
Comment on attachment 355449 [details] Fixes the bug View in context: https://bugs.webkit.org/attachment.cgi?id=355449&action=review >> Source/WebCore/editing/Editor.cpp:209 >> + if (options & TemporarySelectionOption::EnableAppearanceUpdates) > > We should make option an OptionSet. options is totally an OptionSet. >> Source/WebCore/editing/Editor.cpp:227 >> + if (m_options & TemporarySelectionOption::IgnoreSelectionChanges) { > > We should make m_option an OptionSet. It IS an OptionSet.
Daniel Bates
Comment 17 2018-11-21 23:49:20 PST
(In reply to Ryosuke Niwa from comment #16) > Comment on attachment 355449 [details] > Fixes the bug > > View in context: > https://bugs.webkit.org/attachment.cgi?id=355449&action=review > > >> Source/WebCore/editing/Editor.cpp:209 > >> + if (options & TemporarySelectionOption::EnableAppearanceUpdates) > > > > We should make option an OptionSet. > > options is totally an OptionSet. > > >> Source/WebCore/editing/Editor.cpp:227 > >> + if (m_options & TemporarySelectionOption::IgnoreSelectionChanges) { > > > > We should make m_option an OptionSet. > > It IS an OptionSet. Cool. I guess I was looking for .contains() over & :/
fellaslimspam
Comment 18 2019-02-28 22:14:06 PST
This bug is still present in Safari Version 12.0.3 (14606.4.5). Tested on macOS Mojave Version 10.14.3 (18D109) MacBook Pro (Retina, 13-inch, Early 2015) Test case: Two inputs with a value (entered by user or directly set). 1) Click on the first input field. Results in 1 focus event on the first input. 2) Click on the text within the second input field. Results in 3 focus events (second input, first input, second input) 3) Click beside the text in the first input. Results in 1 focus event on the first input. The bug is persistent. Disabling "Look up & data detectors" in "System Preferences -> Trackpad" fixes the issue.
Ryosuke Niwa
Comment 19 2019-03-01 11:06:20 PST
(In reply to fellaslimspam from comment #18) > This bug is still present in Safari Version 12.0.3 (14606.4.5). > Tested on macOS Mojave Version 10.14.3 (18D109) MacBook Pro (Retina, > 13-inch, Early 2015) That's expected because the fix didn't go into 18D109. Please test it on macOS 10.14.4 and iOS 12.2 betas instead. In general, Apple tends to (at least it has been happening for the last couple of years) include the latest version of WebKit in a major OS update and each OS's respective E-releases. Software updates between major "A" releases and "E" releases such as B, C, and D updates tend not to get all the bug fixes in WebKit.
Mark
Comment 20 2019-04-08 14:51:32 PDT
I'm experiencing the double focus bug. I have updated to OS X 10.14.4 (18E226) and Safari Version 12.1 (14607.1.40.1.4) The bug is also in Safari Technology Preview Release 79 (Safari 12.2, WebKit 14608.1.14
Ryosuke Niwa
Comment 21 2019-04-11 01:24:51 PDT
(In reply to Mark from comment #20) > I'm experiencing the double focus bug. > I have updated to > OS X 10.14.4 (18E226) > and Safari Version 12.1 (14607.1.40.1.4) > > The bug is also in > Safari Technology Preview > Release 79 (Safari 12.2, WebKit 14608.1.14 Oh, interesting. Can you reproduce it using the example in comment #0? If so, would you mind what your settings are in System Preferences > Trackpad? Do you have force click & look up enabled? If not, could you give us reproduction steps?
David
Comment 22 2019-07-15 09:01:40 PDT
OSX 10.14.5 (18F132) Safari 12.1.1 (14607.2.6.1.1) I have the same issue, when i switch to tab it's fire event 'focus' twice, instead of once. You can run following html to test: <html> <div>Times focus called: </div> <div id="focustimes">0</div> </html> <script> var i = 0; window.addEventListener('focus', function(e){ i = i +1; document.getElementById("focustimes").innerHTML = i; }) </script>
David
Comment 23 2019-07-15 09:07:19 PDT
(In reply to David from comment #22) > OSX 10.14.5 (18F132) > Safari 12.1.1 (14607.2.6.1.1) > I have the same issue, when i switch to tab it's fire event 'focus' twice, > instead of once. > You can run following html to test: > > <html> > <div>Times focus called: </div> > <div id="focustimes">0</div> > </html> > <script> > var i = 0; > window.addEventListener('focus', function(e){ > i = i +1; > document.getElementById("focustimes").innerHTML = i; > }) > > </script> I just tried in Safari beta 13.0 (14608.1.32), it has same bug.
Ryosuke Niwa
Comment 24 2020-03-10 23:23:51 PDT
(In reply to David from comment #23) > (In reply to David from comment #22) > > OSX 10.14.5 (18F132) > > Safari 12.1.1 (14607.2.6.1.1) > > I have the same issue, when i switch to tab it's fire event 'focus' twice, > > instead of once. > > You can run following html to test: > > > > <html> > > <div>Times focus called: </div> > > <div id="focustimes">0</div> > > </html> > > <script> > > var i = 0; > > window.addEventListener('focus', function(e){ > > i = i +1; > > document.getElementById("focustimes").innerHTML = i; > > }) > > > > </script> > > I just tried in Safari beta 13.0 (14608.1.32), it has same bug. Is this still happening in the latest betas of Safari 13.1? If so, could you file a new bug?
Note You need to log in before you can comment on or make changes to this bug.