Simulating a mousedown, click, mouseup sequence in Tampermonkey?
Asked Answered
F

3

70

I would like to simulate a whole click not just

document.getElementsByClassName()[0].click();

How do I do that? Search results all seem to be about handling such events, not triggering them.

Frescobaldi answered 3/6, 2014 at 21:24 Comment(6)
you can use document.createEvent("MouseEvents") to simulate a click.Phototypy
I thought this was only for things such as scroll wheelFrescobaldi
developer.mozilla.org/en-US/docs/Web/API/…Phototypy
I dont understand how its simulating a whole mouse click without mousedown or mouseup =/ I dont know if what im trying to do is pointless or im just going about it the wrong way, basically I have a button that only works on mouseup.Frescobaldi
well, type in the above code can be mouseup, mouseover, mousemove, or mouseout. the advantage there is that it (ideally) hits inline events (elm.onmouseup()), jQuery events ($(elm).trigger), and addEventListener-based events ( elm.dispatchEvent ) in one swoop. or, you can hit one the above event kinds manually without createEvent, whatever works...Phototypy
Woo!!! The mozilla dev site did it for me. The key for me was: var simMousedownEvent = new MouseEvent('mousedown', { 'view': window, 'bubbles': true, 'cancelable': true }); $(“input.myelement”)[0].dispatchEvent(simMousedownEvent) The [0] is needed to convert from jQuery object to native JS DOM object.Homely
C
138

Send mouse events. Like so:

//--- Get the first link that has "stackoverflow" in its URL.
var targetNode = document.querySelector ("a[href*='stackoverflow']");
if (targetNode) {
    //--- Simulate a natural mouse-click sequence.
    triggerMouseEvent (targetNode, "mouseover");
    triggerMouseEvent (targetNode, "mousedown");
    triggerMouseEvent (targetNode, "mouseup");
    triggerMouseEvent (targetNode, "click");
}
else
    console.log ("*** Target node not found!");

function triggerMouseEvent (node, eventType) {
    var clickEvent = new Event(eventType, { bubbles: true, cancelable: true });
    node.dispatchEvent (clickEvent);
}

That works if the web page is statically loaded. If the web page is AJAX-driven, use a technique as in:


Beware:
The question code has an error. You need to pass a class name to that function. Like so:

document.getElementsByClassName ("SomeClassName")[0].click();
Cosmism answered 3/6, 2014 at 23:23 Comment(9)
You were not right in the sequence of native event firing. Click event is fired after mouseup. In case of double click the sequence is: mousedown, mouseup, click, mousedown, mouseup, click, dblclick. Be aware when relying on click event there is no builtin mechanism to distinguish between single and double clicks. I've suggested an edit of your answer. I hope you feel comfort with that.Ranitta
As far as I know this behavior isn't very new. Up/down are basic events fired immediately and click or drag are composed when other conditions are matching. mouseup within the same Element the latest mousedown event has been targeted to is considered as click, likewise mousemove over a distance treshold while button is held as drag (when draggeble), similary select. Since mouseup is a hard fact while click is open to interpretation subsequently, this order should also be the expectable one.Ranitta
Your code works perfect even when another methods fails! But please, can you add some code to simulate Shift Click?Licketysplit
@jsv, See here and here, or open a new question if you need to. Any new question should have an MCVE or link to a target page since the approach can differ based on the page and your end goal.Cosmism
@BrockAdams, so I posted it here. Hope it is not too wordy!Licketysplit
Firing mouse events doesn't seem to make the browser actually do things. It connects up to javascript listeners on those events, but things handled in the browser don't happen. Specifically, see https://mcmap.net/q/281158/-mouseup-lost-when-leaving-iframe-leads-to-reversed-input/864696 . Mouseup event lost because of cross domain iframe; dispatching a new mouse event, even inside the iframe, doesn't make the mouse stop moving the insertion point in the textbox.Allnight
@RossPresser, javascript can't fire "trusted" events nor events on browser "Chrome" elements. TM and GM could provide some of that capability but currently do not. Your question looks to be about a strange edge case and possible bug.Cosmism
@BrockAdams - thanks for looking. It certainly is strange, and it happens only in Chromium based browsers. The linked Chromium bug had an answer that seemed to indicate they chose this behavior in order to support an edge case in Google Maps... anyway, very off topic for this question, so I'll stop here.Allnight
Warning: Many methods used with createEvent, such as initCustomEvent, are deprecated. Use event constructors instead. developer.mozilla.org/en-US/docs/Web/API/Document/createEventHyperemia
P
23

I improved Brock's code a little after it worked as expected for me.

Definition:

function simulateMouseClick(targetNode) {
    function triggerMouseEvent(targetNode, eventType) {
        var clickEvent = document.createEvent('MouseEvents');
        clickEvent.initEvent(eventType, true, true);
        targetNode.dispatchEvent(clickEvent);
    }
    ["mouseover", "mousedown", "mouseup", "click"].forEach(function(eventType) { 
        triggerMouseEvent(targetNode, eventType);
    });
}

Calling examples:

simulateMouseClick(document);

simulateMouseClick(document.querySelector("a[href*='stackoverflow']"));
Pacificism answered 28/9, 2018 at 6:1 Comment(0)
S
8

Bit Optimized

function fireMouseEvents( query, eventNames ){
    var element = document.querySelector(query);
    if(element && eventNames && eventNames.length){
        for(var index in eventNames){
            var eventName = eventNames[index];
            if(element.fireEvent ){
                element.fireEvent( 'on' + eventName );     
            } else {   
                var eventObject = document.createEvent( 'MouseEvents' );
                eventObject.initEvent( eventName, true, false );
                element.dispatchEvent(eventObject);
            }
        }
    }
}

You would fire like this

fireMouseEvents("a[href*='stackoverflow']",['mouseover','mousedown','mouseup','click']);
Steels answered 22/4, 2017 at 10:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.