Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect middle button click (scroll button) with jQuery

I have a list with a tags to play some mp3 files onclick. It is working fine when binding on the 'click' event with jQuery:

$oo.data({'__mp3play':true,'wapiHandle':h+0,'wapiIndex':o.ajaxPlayList[h].length})
           .bind( 'click', function()
            { var wh = $j(this).data('wapiHandle');
              if( typeof o.regObjects[wh] == 'object' && o.regObjects[wh].play(this.href))
               { return false; }
            });

When clicking the left mouse button: It disables default handling when my flash plugin is loaded otherwise it will be opened normally.

BUT: When I use the scrollbutton of the mouse and click on it, the click event will not fired and the link opens normally.

I have tried to use mousedown or mouseup events but doesn't help, the link always opens normally with the side effect that the music starts playing also with the flash player.

Also preventDefault() does not work at all.

Can somebody tell me how to detect the middle mouse button click (scroll button click)?

Thank you for your comments.

PS: I have already tried other solutions about the 'middle button' available on this site.

Tested in all kind of browsers with the same result.

EDIT: This also does not work, the link will be opened normally when using the middle mouse button. When using the left mouse button, nothing happen.

$oo.bind( 'mousedown click mouseup', function(e)
{ e.preventDefault(); e.stopPropagation(); return false; });
like image 287
Codebeat Avatar asked Mar 22 '11 13:03

Codebeat


5 Answers

Well after a quick test it seems that the three are ordered as follows:

  • Left - 1
  • Middle - 2
  • Right - 3

So if you had:

$(document).mousedown(function(e){
    switch(e.which)
    {
        case 1:
            //left Click
        break;
        case 2:
            //middle Click
        break;
        case 3:
            //right Click
        break;
    }
    return true;// to allow the browser to know that we handled it.
});
like image 159
RobertPitt Avatar answered Nov 11 '22 15:11

RobertPitt


Please don't fire click actions during the mousedown event. It ignores the rest of the event pipeline and goes against current user expectations and design practices.

Problem

Here's a look at the normal order of events that fire for each click type:

$(document).on("mousedown mouseup click focus blur",function(e) {
  console.log("{" + e.which + ":" + e.type + "}"); 
});    

Click Events

Typically, we handle the very last click event because it signifies the users final intent to proceed with the current action.

The click event is fired when a pointing device button (usually a mouse's primary button) is pressed and released on a single element.

Unfortunately, middle mouse presses do not fire such an event (probably because doing so would force developers listening to the click event to distinguish between multiple possible invocations). But if we want to wire up actions against the middle click, we should follow the same UX expectations.

Solution

We'll listen for mousedown events and immediately attach a one time use handler for mouseup events. If the middle key was pressed and if the elements match, we'll trigger our own custom event with type middleclick, which we'll seed from the original event.

$(document).on("mousedown", function (e1) {
  $(document).one("mouseup", function (e2) {
    if (e1.which == 2 && e1.target == e2.target) {
      var e3 = $.event.fix(e2);
      e3.type = "middleclick";
      $(e2.target).trigger(e3)
    }
  });
});

That'll help separate out determining if the middle button was clicked with how we we want to handle it in that case, so we can setup a listener for our custom event type like this:

$(document).on("middleclick", function (e) {
    console.log("{" + e.target.nodeName.toLowerCase() + ":" + e.type + "}"); 
});

Working Demo in jsFiddle and Stack Snippets:

$(document).on("mousedown", function (e1) {
  $(document).one("mouseup", function (e2) {
    if (e1.which == 2 && e1.target == e2.target) {
    	var e3 = $.event.fix(e2);
      e3.type = "middleclick";
      $(e2.target).trigger(e3)
    }
  });
});

$(document).on("middleclick", function (e) {
  console.log("{" + e.target.nodeName.toLowerCase() + ":" + e.type + "}"); 
});

$(document).on("mousedown mouseup click focus blur",function(e) {
  console.log("{" + e.which + ":" + e.type + "}"); 
}); 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>

<div  style="background:#31965a;color:white;width:100px;height:100px;line-height:100px;text-align:center;">
  Click Me!
</div>

* Tested in Chrome, FF, Edge, & IE11

like image 17
KyleMit Avatar answered Nov 11 '22 16:11

KyleMit


Ok, I think I've got it. Here's a fiddle that seems to work. The trick (at least with FF4) seems to be to bind a click handler to the document and have it stop the propagation.

$(document).click(function(e){
        //not checking for the right click will prevent the context-menu from showing, you may or may not want to do that
        if (e.which != 3) { 
            e.preventDefault();
            return false;
        }
    });

This solution was found on this forum page.

like image 8
no.good.at.coding Avatar answered Nov 11 '22 15:11

no.good.at.coding


Okay guys,

Thank you for your input. '@no.good.at.coding' has a nice solution but does not work on IE (see later on this writing) but is a good starting point. I change his code to this:

// Avoid relations will be opened in extra tab when clicking middle-scroll-button to open it
$(document).bind($.browser.msie ? "mousedown" : "click", function(e)
{
    if (e.which == 2 && e.target.tagName == 'A') 
    {
        var bIE = $.browser.msie,
            $o = $(e.target),
            oe = $o.data('events'),
            b = true,
            f = function(){};

        if (typeof oe == 'object' && oe['click']) {
            f = function(){ $o.trigger('click'); }
        } else {
            b = (typeof $o[0].href == 'string' && ($o[0].target == undefined || $o[0].target == '' || $o[0].target == '_self'));
            if (b) { 
                f = function () { window.location.href=$o[0].href; };
            }
        }

        if (!b) { return; }

        e.stopImmediatePropagation();
        e.stopPropagation();
        e.preventDefault();

        if (bIE)
        {
            if (!window.__swcp__) { 
                window.__swcp__= $('<div style="position:fixed;top:0px;left:0px;width:100%;height:100%;background:#000;display:block;z-index:9999;opacity:0.01;filter:alpha(opacity:1);" />').appendTo('body'); 
            }
            window.__swcp__.show();
        }

        setTimeout(f, 50);
        if (bIE) { 
            setTimeout( function() { window.__swcp__.hide(); }, 1000 );
        }

        return false;
    }
});

The middle-button acts now like the left-button of a mouse. As you can see IE needs some more, we must unfocus the link tag for 1 second to avoid that it will be opened in an extra tab. I use here a simple way to do this, create a 'for the eye" transparent div (opacity = 0.01) that will be placed over the window content so any link on the page will be unfocused. The user will not notice any difference except that the mouse pointer can change from pointer to default and after one second it change back to pointer (IE only). I can live with that.

I accept this as an answer, but if you have better idea's let me know.

like image 3
Codebeat Avatar answered Nov 11 '22 14:11

Codebeat


The correct way to do this with HTML5 is to use auxclick event.

For example, to fully disable middle mouse button click on an element

    $element.on("auxclick.disablemiddleclick", function(e)
    {
        // https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event
        if (e.which === 2 && e.cancelable) // disable middle button click
        {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
            console.log("disabled middle click, e=", e);
        }
    });

(The suffix on "auxclick" handler name is meant to allow for easy removal of this handler with $element.off("auxclick.disablemiddleclick") without keeping track of the function reference.)

like image 1
Mikko Rantalainen Avatar answered Nov 11 '22 14:11

Mikko Rantalainen