2 ELEMENT 2 FURIOUS

12 Nov 2015

Both Bug 1205244 and webcompat bug #1886 reported an issue where Firefox users can’t select menu items from a flyout-style menu in the Steam store website, but it’s working in other browsers.

Web pages, amirite? (yes, mike. u r rite.)

The offending code is here, so put on your retro bug hunting hats and see if it jumps out to you:

$J(document).on('mouseleave.Flyout', '.flyout_tab', function(e) {
  ...
  if ( !$Content.length ||
       $Content.data('flyout-event-running') ||
       bResponsiveSlidedownMenu ||
       $Content.is( e.toElement ) ||
       $J.contains( $Content[0], e.toElement ) )
      return;

. . . . . . . .

In the likely case that you weren’t developing sites during the DHMTL glory days (I sure wasn’t), the bug is: e.toElement.

event.toElement is an IE4-ism that WebKit added or possibly inherited from KHTML for compatibility with IE. (I’m willing to eat my bug hunting hat if it wasn’t added to fix a bunch of broken DHTML menus back in the day.)

The standard MouseEvent property to use when you’re trying to figure out what element you’re on after a mouseout or mouseleave event is event.relatedTarget. This is the one that is supported basically everywhere (in IE since version 9), and like, exists in a spec.

(And if you’re into C++ or whatever, you can see that WebKit’s event.toElement is just an alias for relatedTarget.)

Prototype.js—which the Valve site uses in various places—knew this property was goofy so it extends the event object with a polyfilled relatedTarget, but naturally only for IE.

if (window.attachEvent) {
  function _relatedTarget(event) {
    var element;
    switch (event.type) {
      case 'mouseover':
      case 'mouseenter':
        element = event.fromElement;
        break;
      case 'mouseout':
      case 'mouseleave':
        element = event.toElement;
        break;
      default:
        return null;
    }
    return Element.extend(element);
  }
  ...
  Object.extend(event, {
    ...
    relatedTarget: _relatedTarget(event),
    ...
  });

You might be thinking, uh oh, Edge dropped support for attachEvent, this should be broken there too! But they’ve apparently kept that for compat reasons (simple test here). So yay I guess.

Anyways. The good folks at Valve have fixed the menu internally and it should be possible to buy {insert hilarious video game joke so people think I’m cool here} from a dropdown menu item using Firefox (or any other future browser that doesn’t implement this quirk). If you happen to have commit access to any code using toElement feel free to rip it out and replace it with relatedTarget.