Page MenuHomePhabricator

Don't mutate DOM on touch-originated cursor events in Differential
ClosedPublic

Authored by epriestley on Jan 29 2016, 1:49 PM.
Tags
None
Referenced Files
Unknown Object (File)
Wed, Dec 11, 7:16 PM
Unknown Object (File)
Sun, Dec 8, 5:54 AM
Unknown Object (File)
Fri, Dec 6, 6:15 AM
Unknown Object (File)
Fri, Dec 6, 4:36 AM
Unknown Object (File)
Wed, Dec 4, 7:36 PM
Unknown Object (File)
Wed, Dec 4, 4:29 AM
Unknown Object (File)
Mon, Dec 2, 1:23 PM
Unknown Object (File)
Sat, Nov 30, 10:26 AM
Subscribers

Details

Summary

Fixes T10229. Broadly:

  • When the user hovers over a line number or inline comment, we update the yellow reticle to highlight the relevant lines. Specifically, this is in response to a mouseover event.
  • On touch devices, touches fire mouseover and if you mutate the DOM inside the event, the device aborts the touch.

To remedy this:

  • Distingiush between mouse-originated and touch-originated cursor events.
    • We do this, roughly, by setting a flag when we see "touchstart", and clearing it when we see the second copy of any unique cursor event.
    • This method is complex, but should be robust to any implementation differences between devices (for example, it will work no matter which order the events are fired in).
    • This method should also produce the correct results on weird devices that have both mouse-devices and touch-devices available for cursor input.
  • When we see a touch-originated mouseover or mouseout, don't mutate the DOM.
  • Put an extra DOM mutation into the click event to improve highlighting behavior on touch devices.
Test Plan
  • In iOS Simulator (4s, iOS 9.2), clicked various inline actions ("Reply", "Hide", "Done", "Cancel", line numbers, etc). Got responses after a single touch.
  • Verified hover + click behavior on a desktop.
  • Logged and examined a bunch of events as a general sanity check.

Diff Detail

Repository
rP Phabricator
Branch
doubletouch2
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 10380
Build 12666: Run Core Tests
Build 12665: arc lint + arc unit

Event Timeline

epriestley retitled this revision from to Don't mutate DOM on touch-originated cursor events in Differential.
epriestley updated this object.
epriestley edited the test plan for this revision. (Show Details)
epriestley added a reviewer: chad.

(Sorry to butt in here, I don't know the culture of the Phabricator project and maybe it's considered impolite to post diff comments as a stranger. I apologise if that's the case.)

This looks good to me. The only thing is that on "weird" devices with touch and a mouse, I think this code would disable the mouse hover highlighting until the next mouse click following a touch. It'd go like this:

  1. A touchstart event activates "touch mode" for all coming events.
  2. More than 1 occurrence of mousedown, mouseup or click is required to deactivate "touch mode".
  3. ...but no such event will arrive if we have a "content change aborts touch event" situation. In this cases the last event we'll see is a mouseover event.
  4. ...and even if we don't, only 1 of each event will arrive for a single touch.

So the flag won't be reset until the user clicks somewhere. Which is probably okay, just technically a minor bug.

webroot/rsrc/js/application/differential/behavior-edit-inline-comments.js
321–323

Actually, although it's fine either way, I think we did highlight the affected lines.

We did not on the mouseover event, due to the new L301, but we did later on the mousedown event (L190). mousedown simulation comes before click so at the time of this handler the work should already have been done.

(Incidentally the mousedown does not need to be special cased for touch because changing the DOM at this point does not cancel the event.)

webroot/rsrc/js/application/differential/behavior-edit-inline-comments.js
321–323

L190 is only for clicks on <th> tags (the line numbers), and does not fire for clicks on the inline comment actions (reply, hide, etc).

I think you're right about the other case, but I don't think we can easily accommodate it without either encoding more information about how devices work or tracking more information about event handling. The complexity in either case doesn't seem worthwhile to me, although maybe devices which support both input methods are more widespread than I believe (is it common to use Surface tablets with mice?)

The advantages of the current approach are:

  • it's relatively simple;
  • it will work regardless of the order devices fire the events in: one browser doing "touchstart, touchend, mousedown, click, mouseup" and another doing "touchstart, mousedown, click, mouseup, touchend" will work. From briefly googling, it seems like there's a lot of diversity in what browsers do;
  • it will work regardless of which events fire: if some events do not fire (because an earlier event was killed by the application, or a user aborted the touch by tapping more fingers) we'll get back to the right state on the next event.

We could make it more complex (track aborted events, track 'touchcancel') or possibly encode more user agent behavior, but the specific case of "hover doesn't work between the time you touch the screen and the next time you click, if you're using a device with both touch-device and mouse-device cursor input methods" doesn't seem worth the effort -- at least right now, when we have no knowledge of any users with such devices.

(The whole approach is also probably garbage for multi-touch inputs, but that's a whole separate can of worms.)

... the specific case of "hover doesn't work between the time you touch the screen and the next time you click, if you're using a device with both touch-device and mouse-device cursor input methods" doesn't seem worth the effort -- at least right now, when we have no knowledge of any users with such devices.

Yeah this sounds like a classic issue to postpone until someone actually cares.

(Although for that day, a simple setTimeout to clear the flag after 1 s will probably do the trick. The delay needs to be "somewhat longer" than 300 ms due to the delay between touch and simulated events, and we can't know exactly how much longer "somewhat" is since that depends on the device. At the same time 1 s is short enough that it'd be quite difficult for a user to switch between touch and mouse interaction so fast that they'd ever notice the workaround.)

Like you said, it doesn't matter. The above will do the job and it's definitely nice not to have to make assumptions about the event ordering.

Yeah, I think that's a pretty reasonable approach to try should we encounter touchey-mouse devices in the wild.

chad edited edge metadata.
This revision is now accepted and ready to land.Jan 29 2016, 2:54 PM
This revision was automatically updated to reflect the committed changes.