Simulating a mousedown, click, mouseup sequence in Tampermonkey?

66,779

Solution 1

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 = document.createEvent ('MouseEvents');
    clickEvent.initEvent (eventType, true, 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();

Solution 2

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']"));

Solution 3

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']);
Share:
66,779
user3699068
Author by

user3699068

Updated on September 28, 2020

Comments

  • user3699068
    user3699068 over 3 years

    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.

  • Pinke Helga
    Pinke Helga almost 10 years
    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.
  • Pinke Helga
    Pinke Helga almost 10 years
    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.
  • user90726
    user90726 over 8 years
    Your code works perfect even when another methods fails! But please, can you add some code to simulate Shift Click?
  • Brock Adams
    Brock Adams over 8 years
    @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.
  • user90726
    user90726 over 8 years
    @BrockAdams, so I posted it here. Hope it is not too wordy!
  • Ross Presser
    Ross Presser over 5 years
    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 stackoverflow.com/q/52208673/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.
  • Brock Adams
    Brock Adams over 5 years
    @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.
  • Ross Presser
    Ross Presser over 5 years
    @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.
  • Iglesias Leonardo
    Iglesias Leonardo about 2 years
    Warning: Many methods used with createEvent, such as initCustomEvent, are deprecated. Use event constructors instead. developer.mozilla.org/en-US/docs/Web/API/Document/createEven‌​t