Detect middle button click (scroll button) with jQuery
Asked Answered
A

7

23

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; });
Areopagus answered 22/3, 2011 at 13:59 Comment(8)
Why would you expect click to be invoked for a middle-click? They're not the same - you wouldn't expect it for right-click would you? And what did you try with the mousedown approach? Did you check the event.which property to identify which button had been pressed?Kliman
The middle-click will be handled the same as a left-mouse-click, the A-tag will be opened so you can assume that a left-mouse-click is the same as a middle-click. If not, like you just said, what is the name of the middle-click event? Event.which does not make any difference, you can test if the middle button is pressed but you cannot suppress the default behaviour of the middle button because there is another event involved? The link is still opened normally.Areopagus
Your assumption is false - just because the left mouse click shows behaviour similar to the middle click doesn't mean that they're the same internally. In fact, they're not - click is not fired when the middle mouse button is clicked. However, it turns out you're correct about the preventDefault() and stopPropagation() not having any effect and I can't think of any workaround at the moment. Here's a fiddle that shows how far I got with this using mousedown and mouseupKliman
check out my answer and fiddle below, I found a forum post that suggested a way to get this to work.Kliman
Does this answer your question? Jquery: detect if middle or right mouse button is clicked, if so, do this:Amaris
@AdvaitJunnarkar No, because the accepted answer provides the same solution (of detection) and also suppress a behaviour of IE only (detection only wasn't enough). This is a pretty old question, 8 years old and partly IE related. IE is dead, history, so why bother with a 'new' solution? There is already a solution and is better, more advanced.Areopagus
@Areopagus Neither the question nor the accepted answer mentions IE. This question might be old and your specific problem may not be common anymore, but this general problem is still relevant. SO is supposed to be like a wiki so there's nothing wrong with updating old articles.Amaris
@AdvaitJunnarkar: 1. At the accepted answer: "As you can see IE needs some more......". 2. SO is not (supposed to be) a wiki, it is a QA site. 3. The accepted answer provides the same solution of detection and is more advanched so yours is not an update.Areopagus
A
3

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.

Areopagus answered 22/3, 2011 at 17:13 Comment(6)
Note that jquery.browser has since become deprecated. api.jquery.com/jQuery.browserCyme
Frisberarian < Thanks for the additional info. At the time IE9 was around for the first time I discover some problems with newer versions of jQuery higher than v1.5.1. That's the reason I still use a slightly modified version of v1.5.1 today that is working okay in all browsers of today (including the old and mobile ones). Also some older code and plugins doesn't work with the newer jQuery versions because there are so many changes (= too much extra work), i will stay at v1.5.1 until it is really necessary to change.Areopagus
Sorry if my edit seems aggressive, but it was just so hard to make sense of. I tried to leave the variables as is, but they really should be renamed and I think some refactoring, such as reuse of the browser checking might be a good idea.Barren
Thanks Nenotiep. Well, some things are the style you prefer. I don't like the accolade style, always difficult to read because you cannot see statements directly, never understood why they are not aligned to each-other. Variables, I know, but it javascript must be compact for speed. Nowadays I use google enclosure compiler to minify the scripts. Besides, it is always important to look at what happen in the code instead of look at the variable names. Sure, a clear variable name can clearify things, because javascript has no declaration type it can be anything. Don't rely 2 much on var names.Areopagus
..... (continue comment above) When you can read this, you can read almost anything. I use always var names starting with the expected type (letter) of the variable. o = object, $ = jQuery object, b = boolean, s = string, i = integer, e = event, f = function etc.Areopagus
..... (continue comment above) When you can read this, you can read almost anything. I use always var names starting with the expected type (letter) of the variable. o = object, $ = jQuery object, b = boolean, s = string, i = integer, e = event, f = function etc. I bet, you can now read it easier knowing this. A hint to an expected type is, to me, more useful than a beautiful variable name as long the function name is clear enough. Power of jQuery = compact. if you cannot handle that, use another framework lib.Areopagus
C
56

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.
});
Conventioneer answered 22/3, 2011 at 15:26 Comment(1)
I know, i know, but that's not the case of the problemAreopagus
E
17

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

Elkins answered 8/3, 2018 at 17:9 Comment(6)
Appreciate your answer however there are some issues. You wrote; "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." Eh, at first, it doesn't fire anything, it doesn't cause a hardware event by itself and doesn't fire a click event however it handles an event and can cancel an event. And because you don't cancel anything in the route to a click it can lead to unpredictable results when there are other attached event handlers. I have already posted a solution/workaround 2 this.Areopagus
@Codebeat, I appreciate the comment (but not sure about the downvote). I'm not sure our solutions are looking to address the same issue. My point is that this answers actually handles a middle mouse click event, not just a middle mouse mousedown event. Click events happen when the user has clicked down and released on the same element. When you middle mouse click on a link, in all browsers it will open that link when you've let go, not when you've depressed the button. It gives you time to cancel out. If you're looking to replicate this functionality, you'll need this asrElkins
This question is 7 years old and also the answer, I believe I did '$.browser.msie ? "mousedown" : "click"' for a reason. Also I use the document element (like you do) to preview actions so before the event reaches the focused element. That's why I cancel the event. If you cancel an event all other related events will be ignored and because of that there is no click at all because the action has not been completed. In your example, you don't cancel anything and that's why you still receive all events on the document and focussed element. Goal was to suppress behavior be4 the action willb proce.Areopagus
I see a downvote on my question and answer on yesterday, hopefully your not the one who did this because you are angry in all frustration. I don't know what exactly your problem is and why you want to do want you want to do, with an extra handler and such.. Your answer must be a comment. There was a reason for the differences in mousedown (iE) and click (others) 7 years ago. Again, the goal was to suppress a hardware behavior before the action will be processed on any link (and IE requires that 7 years ago) and to avoid the need to bind an extra event handler on every element. .....Areopagus
........ If you don't cancel the event, it doesn't work at all. And I don't fire click and such. Really, I don't understand what your point must be, maybe you don't understand how events works. And also, it isn't an answer to the question. You want to discus the answer and not the question and that could be a comment.Areopagus
Aha (ploink), I think you don't understand this line: '$.browser.msie ? "mousedown" : "click"' which is actually an if-then-else statement. I don't bind an event on mousedown and click at the same time. For IE I do it on "mousedown" and for others I do it on "click". That is what your point is about, you think that I handle both and that's not true.Areopagus
K
8

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.

Kliman answered 22/3, 2011 at 15:14 Comment(0)
A
3

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.

Areopagus answered 22/3, 2011 at 17:13 Comment(6)
Note that jquery.browser has since become deprecated. api.jquery.com/jQuery.browserCyme
Frisberarian < Thanks for the additional info. At the time IE9 was around for the first time I discover some problems with newer versions of jQuery higher than v1.5.1. That's the reason I still use a slightly modified version of v1.5.1 today that is working okay in all browsers of today (including the old and mobile ones). Also some older code and plugins doesn't work with the newer jQuery versions because there are so many changes (= too much extra work), i will stay at v1.5.1 until it is really necessary to change.Areopagus
Sorry if my edit seems aggressive, but it was just so hard to make sense of. I tried to leave the variables as is, but they really should be renamed and I think some refactoring, such as reuse of the browser checking might be a good idea.Barren
Thanks Nenotiep. Well, some things are the style you prefer. I don't like the accolade style, always difficult to read because you cannot see statements directly, never understood why they are not aligned to each-other. Variables, I know, but it javascript must be compact for speed. Nowadays I use google enclosure compiler to minify the scripts. Besides, it is always important to look at what happen in the code instead of look at the variable names. Sure, a clear variable name can clearify things, because javascript has no declaration type it can be anything. Don't rely 2 much on var names.Areopagus
..... (continue comment above) When you can read this, you can read almost anything. I use always var names starting with the expected type (letter) of the variable. o = object, $ = jQuery object, b = boolean, s = string, i = integer, e = event, f = function etc.Areopagus
..... (continue comment above) When you can read this, you can read almost anything. I use always var names starting with the expected type (letter) of the variable. o = object, $ = jQuery object, b = boolean, s = string, i = integer, e = event, f = function etc. I bet, you can now read it easier knowing this. A hint to an expected type is, to me, more useful than a beautiful variable name as long the function name is clear enough. Power of jQuery = compact. if you cannot handle that, use another framework lib.Areopagus
F
1

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.)

Frunze answered 24/3, 2021 at 13:26 Comment(2)
Valid answer for nowadays (take a look at the support version numbers) however this question is almost 10 years old! 10 years ago this was not supported by IE for example.Areopagus
Yeah, the only way MSIE and HTML5 fit is the sentence "MSIE doesn't support HTML5".Frunze
T
-1

e.which should do it:

Simple example:

$(document).ready(function(){
    $(document).mousedown(function(e){
         alert(e.which); // ##=> left
    }) 
})
Teratoid answered 22/3, 2011 at 15:0 Comment(2)
This is not the answer to the question and also not an answer at allAreopagus
No, it doesn't - the trouble is that the browser handles the middle click and it still opens a new tab/window when a link is middle clicked. See my fiddle in the comments above.Kliman
G
-3

If you, (like me) found this because of weird-o middle click bugs from clients. And you just want any middle or right click to behave like a left click

Forget all that lame code for IE.

Short and sweet:

$(document).click(function(e){
  // checking for any non left click and convert to left click.
  if (e.which != 1) { 
    e.which = 1;
  }
});

Obviously if you need a little more discrimination, you can do something like:

$('a.no-non-left-clickies').click(function(e){
  // checking for any non left click and convert to left click.
  if (e.which != 1) { 
    e.which = 1;
  }
});
Ghiselin answered 16/1, 2013 at 19:34 Comment(2)
Well, I looked in more detail at your initial question, and I see that you do need more IE junk than I mentioned, however, my statement still stands, in general. If you want a quick-o-change-o convert middle or right click into a left click, the above simple code will work on all browsers I've tested on.Ghiselin
Have not tried your solution but does it also avoid that a new page is opened?Areopagus

© 2022 - 2024 — McMap. All rights reserved.