The ideal behavior of the top bar buttons should satisfy the following goals:
When clicked normally, in a browser that supports JavaScript, they should open/close the menu.
If the menu cannot be opened yet, because the necessary scripts have not yet loaded, the button should either do nothing, or the menu opening should be deferred until it can be done.
If JavaScript is not supported or enabled, the buttons should default to working like normal links.
In any case, middle-clicking the buttons should always act as if they were normal links, opening the target page in a new tab.
The current implementation, which defines the buttons as normal links in the HTML, and then later adds a jQuery event handler to catch normal mouse clicks and toggle the menu, meets all these goals except #2.* The reason it doesn't meet that goal is because it takes as while for jQuery and the SE framework to load, and until then, the buttons act like normal links.
There are several ways in which this could be fixed without compromising the other goals:
The buttons could be marked in the HTML with old-style onclick
handlers that stopped them from working as normal links (and, optionally, recorded the clicks for deferred execution) until the jQuery code loads, at which point these handlers could be removed and replaced by the real menu toggling handler.
Alternatively, some in-line JavaScript code, embedded in the HTML immediately after the buttons, could inject temporary event handlers that achieve the same purpose. This might leave a small window of vulnerability between the loading of the buttons and the execution of the code, but it should at least significantly reduce the problem.
Even better, some inline JavaScript, embedded in the HTML before the buttons, could add a click event handler on one of their parent elements (such as the .topbar
div) that detected clicks targeting the buttons and disabled their normal operation. Conveniently, this handler would not even need to be removed later, since the real menu toggle handlers would pre-empt it.
The next version of the SOUP user script will include a client-side implementation of the last option above (assuming that this bug isn't fixed before its release). Adventurous users can grab the pre-release development version from the GitHub repo here. For the merely curious, here's what the code looks like:
var buttonRegex = /(^|\s)js-(site-switcher|inbox|achievements|help)-button(\s|$)/;
document.addEventListener( 'click', function (event) {
if ( event.button != 0 ) return; // ignore right/middle clicks
var elem = event.target;
while ( elem && !buttonRegex.test(elem.className) ) elem = elem.parentNode;
if ( elem ) event.preventDefault();
}, false );
(The event handler is set on the root document object, because at the time the user script runs, there's no guarantee that any other part of the DOM is present yet. In a proper SE-side fix, the handler could be installed on a closer parent element of the buttons.)
* Well, in Firefox it does, at least. In Chrome, middle-clicking seems to also toggle the menu, which is probably a bug, or at least a misfeature (being neither expected nor useful behavior, for users used to middle-clicks opening a new tab). It does seem to be a different bug from this one, though. Also, currently only the site switcher menu actually has a useful middle-click / no-JS behavior; the others just have href="#"
.