methodofaction
methodofaction

Reputation: 72465

jQuery detect mousedown inside an element and then mouseup outside the element

I have something similar to a drawing canvas, and I capture it's state on mouseup for undo purposes. The canvas isn't full screen, so you can draw with a brush and release outside the canvas. Something like this:

$("#element").mousedown(function(){
  $(document).mouseup(function(){
    //do something
  }); 
});

But this doesn't work of course. A plain $(document).mouseup doesn't work either, because I have many other UI elements and it saves the state each time you click on a UI element.

Any ideas?

Upvotes: 17

Views: 24349

Answers (5)

louisinhongkong
louisinhongkong

Reputation: 561

If you've got a lot of clickable elements like I have, you're gonna want to create a global mouse catcher and set your mouseup code within the mousedowns of clicked element. Here's the code I used.

    var MouseCatcher=function()
    {
        this.init=function()
        {
            var mc = this; 
            $(document).bind({
                mouseup:function(e) 
                {
                    mc.mouseup();
                }
            });
        }
        this.mouseup=function()
        {
            return false;
        }
    }
    var mouseCatcher = new MouseCatcher();
    mouseCatcher.init();



    $('#clickableElement').bind({
        mousedown: function(e)
        {
            console.log('mousedown on element');

            mouseCatcher.mouseup=function()
            {
                console.log('mouseup called from MouseCatcher');
                this.mouseup = function(){return false;}
            }

        },
        mouseup:function(e)
        {
            //mouseup within element, no use here.
        }
    });

Upvotes: 0

makeroo
makeroo

Reputation: 527

A possible implementation of mike's and waitingforatrain's answers in GWT. In the html head manage mouse up events (javascript code):

   var mouseUpHook = false;
   $(document).mouseup(function() {
       if (mouseUpHook) {
           mouseUpHook(null);
           mouseUpHook = false;
       }
   });

Let your custom Widget class implement MouseDownHandler and MouseUpHandler, and add those lines in your constructor to receive mouse events (java code):

    addDomHandler(this, MouseDownEvent.getType());
    addDomHandler(this, MouseUpEvent.getType());

Finally, add those methods in your custom Widget class (java and javascript code):

@Override
public void onMouseUp (MouseUpEvent event) {
    removeMouseUpHook();

    // ... do something else
}

private native void hookMouseUp () /*-{
    $wnd.$('body').addClass('noselect');
    var myThis = this;
    $wnd.mouseUpHook = function () {
        [email protected]::onMouseUp(Lcom/google/gwt/event/dom/client/MouseUpEvent;)(null);
    };
}-*/;

private native void removeMouseUpHook () /*-{
    $wnd.$('body').removeClass('noselect');
}-*/;

@Override
public void onMouseDown (MouseDownEvent event) {
    hookMouseUp();

    // ... do something else

    event.preventDefault();
}

Last line is usefull to prevent image dragging. Infact, user-select: none is not sufficent.

Upvotes: 0

bcoughlan
bcoughlan

Reputation: 26627

The above answers will not work when text is selected.

The fix is to stop text from being selected when the mouse is down, and re-enable it when it's back up:

in your CSS:

.noselect {
    /* Prevent text selection */
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -o-user-select: none;
    user-select: none;
}

Then your JS:

var myButtonDown=false;

$('.ff', ffrw).mousedown(function() {
    myButtonDown=true;
    $('body').addClass('noselect');
    //Your code here
});

$(document).mouseup(function() {
    if (myButtonDown) {
        myButtonDown = false;
        $('body').removeClass('noselect');
    }
})

Upvotes: 8

Nick G
Nick G

Reputation: 960

Hopefully you find this little solution to be helpful. You can see it in action here: http://jsfiddle.net/neopreneur/PR2yE/

$(document).ready(function(){
    var startMouseDownElement = null;

    $('#element').mousedown(function(){
        // do whatever
        //...

        // set mousedown start element
        startMouseDownElement = $(this);
    });

    // handle bad mouseup
    // $('#container, #container *').mouseup would be more efficient in a busy DOM
    $('body *').mouseup(function(event){
        event.stopPropagation(); // stop bubbling
        if($(this).attr('id') != $(startMouseDownElement).attr('id')){
            //oops, bad mouseup
            alert('bad mouseup :(');  
        }
    });
});

Upvotes: 2

mike
mike

Reputation: 4433

var isDown = false;

$("#element").mousedown(function(){
    isDown = true;
});

$(document).mouseup(function(){
    if(isDown){
        //do something
        isDown = false;
    }
}); 

For the sake of simplicity I put isDown in the global namespace. In production you would probably want to isolate the scope of that variable.

Upvotes: 34

Related Questions