More on Front-end Events - Click Sensors
Today I was busy learning about how modern web-browsers work. In particular I was experimenting on the link sensors of the smart indicator prototype. While I was busy with debugging the indicator component for Internet Explorer. I realized that also under Firefox the link sensors did not correctly register the link related interactions. In this post I explain the solution I found for this problem.
In my EC-TEL paper I discussed the need for providing learners information on their learning activities, in order to facilitate learning in informal environments. For the prototype that is described in the paper I implement currently all the sensors. For the link selection sensor it turned out that the naive solution of using onclick event handler will miss so many standard events that it is useless for link sensors.
Particularly for fixing the middle button click problem in Firefox I adapted the link counter solution proposed by Ed Eliot. The hidden problem with this approach became obvious, while I tried to understand why Internet Explorer behaved strange in for the link handling. I found the nice analysis of mouse events at http://unixpapa.com and started further reasoning and experimenting with Ed's solution. I figured out that the proposed link tracker approach has some major weaknesses. First, it catches all mouseup events, also those of the right mouse button. This approach triggers the link tracking code even in those cases where the mouseup event would not have caused the browser to follow that link. This happens when the user selects something on the page and ends selecting information in a link. Although this approach counts when the context menu is called on a link, it is not capable to see if he link is followed from within the context menu.
This leads us to a major problem with the W3C event. Although the specification lists a bunch of user interface events, a followlink event was not specified. For web-applications this event would be a major improvement. With the current situation, there is no way to determine when a user selected a link, while a followlink event would be thrown if a user requests a href or src of an HTML element, regardless if this will open a new tab, a new window, or if the operation has been triggered from within the user-interface with a mouse click, a keyboard shortcut, or through a menu.
While I am not able to propose changes to the specification and have certainly not the time to wait until some browser vendor implemented that event, I searched for a cross-browser solution for this problem. The result of this search was that there is no single function approach for cross-browser link sensors. That means one needs at least two independent functions for triggering the sensor event for link tracking. The reason is partly burried in unixpapa.com's mouse event report.
UPDATE In the end I wasn't able to verify the analysis at unixpapa.com. It turns out that Internet Explorer Version 6 (IE6) is completely ignorant with regard to wheel clicks, where Internet Explorer Version 7 (IE7) mimicks the firefox behaviour. That means that IE7 will not throw a click event if a user clicks on the mouse wheel.
The problem is that Firefox does not send the click event if the mouse wheel is clicked. Instead, Firefox will simply report a mousedown and mouseup in that case. Insofar Ed Eliot's approach aims towards the correct solution for the problem. Some testing with Firebug revealed that if a link is clicked and will be opened by the browser, the detail-property of the mouseup-event is set to 1. Thus, if event.detail == 1 then the mouseup is a click. We can solve the problem of registering the wrong events, by checking this additional property for Firefox style browsers.
In traditional object detection, one would now test if the browser is an Internet Explorer style by testing for the event.srcElement and applies the code that is different from Firefox in a special condition. Therefore, the mouseup is not sufficient for link tracking in Internet Explorer as there is no indicator if an underlying link will be followed from within the mouseup event. In the Internet Explorer a link is always followed if either the left or the wheel button were clicked. This means that the indicator if a link will be followed in Internet Explorer is given only by the onclick event.
UPDATE The previous paragraph would have been valid if the analysis provided by unixpapa.com would have been correct. Instead, there is no easy way to figure out if a link has clicked or not. In order to avoid confusion with mouseup's caused by selections, I decided to use a slightly different approach. The solution I came up with makes use of an interesting behaviour of IE7 wheel clicks: in case a wheel click is performed outside of a link, the user will receive the mouse navigation cursor. As a side-effect the browser scripts do not receive an mouseup event. Thus, pushing the mouse wheel and dragging the cursor to a link, will not cause any harm. The event is only available if the wheel has been clicked on the link. For the normal left button click, I use the click event to record the interaction.
The correct link tracing implementation for Firefox and Internet Explorer has two event handlers, which check at different stages of the event system if a link is followed or not. For the example I used the javascript xlib.
The wheel click case
xAddEventListener( elem, 'mouseup', function(e){ if ( e && e.target && e.detail == 1 && e.which==2 ) { // do your work for wheel clicking in firefox } else if ( e && e.srcElement && e.button == 4 ) { // handle the wheel click in IE7 } // common code }, false );
The left button case
xAddEventListener( elem, 'click', function(e){ if ( e && e.target && e.which== 1 ) { // handle the left button in firefox } else if ( e && e.srcElement && e.button == 1 ) ) { // handle the left button in the internet explorer } // common code }, false );
Only the link tracking via the context menu remains impossible. For that purpose I deactivated the context menu in firefox. However, in both version of the Internet Explorer the context menu will still appear and a user can follow a link undetected.
xAddEventListener( elem, 'contextmenu', function(e){ xStopPropagation(e); }, false );