mousemove handler not called with JQuery .mousemove() or .trigger - javascript

when mousemove handler is added with addEventListener(), the handler will never be called
with JQuery simulated event by $(xx).mousemove() or $(xx).trigger(e) where e is a jquery event.
But the listener can be called when the event is simulated with pure JS dispatchEvent.
Anybody can explain? My enviroment is Mac + chrome.
code is here http://jsfiddle.net/eepaul/r8W2h/
<body>
<ul id="id_ul">
<li id="a">oooo</li>
<li id="b">jjjj</li>
</ul>
<p id="console"></p>
</body>
js
var liA = $("li#a")[0];
var ul = $("ul")[0];
var p = $("p#console")[0];
ul.addEventListener("mousemove", function(e) {
$(p).text($(p).text() + "mousemove triggered\n");
}, false);
var event = $.Event("mousemove", {
canBubble:true,
cancelable: true,
view:liA.ownerDocument.defaultView,
detail: 1,
screenX:0, //The coordinates within the entire page
screenY: 0,
clientX: 0, //The coordinates within the viewport
clientY: 0,
ctrlKey:false,
altKey:false,
shiftKey: false,
metaKey:false, //I *think* 'meta' is 'Cmd/Apple' on Mac, and 'Windows key' on Win. Not sure, though!
button: 0, //0 = left, 1 = middle, 2 = right
relatedTarget:null
});
//neither of the following 2 ways can trigger the handler
window.setTimeout(function() {
$(liA).trigger(event);}, 1000);
window.setTimeout(function() {
$(liA).mousemove();}, 1000);

Hmm. seems a known issue in jquery.
http://bugs.jquery.com/ticket/4314

Related

How to make one NOT be able to simulate a click

I've noticed while working for someone on a script that this special button ( the login one ): https://www.easports.com/fifa/ultimate-team/web-app/ does not allow to simulate a click on it in any possible way.
I'm extremely curious to know how they do it.
I've tried
var btn=$('#Login > div > div > button.btn-standard.call-to-action');
btn.click(); // or trigger('click');
// or
click = new Event(click);
btn.dispatchEvent(click);
// or
btn.trigger('mousedown');
// oh and also:
function click(x, y)
{
var ev = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true,
'screenX': x,
'screenY': y
});
var el = document.elementFromPoint(x, y);
el.dispatchEvent(ev);
}
I've even tried mouseenter, followed by mousedown and mouseup;
How can one achieve this sort of feature?
Here's an example of what they might be doing. Event.isTrusted gives you information on if it was a user action or a created event. They probably have some logic around this:
From the docs:
The isTrusted read-only property of the Event interface is a Boolean
that is true when the event was generated by a user action, and false
when the event was created or modified by a script or dispatched via
EventTarget.dispatchEvent().
document.getElementById('btn').addEventListener('click', (e) => console.log(e.isTrusted));
// Simulate a click onload (should print false to the console)
document.getElementById('btn').click(); // false
// TODO: Click the Button manually, you should see 'true' being printed
<button id="btn">Button</button>
My guess is that if you look into their source code, you'd see something similar where they are just doing an .stopPropogation or .preventDefault if isTrusted is false.
So they are probably doing this:
document.getElementById('btn1').addEventListener('click', (e) => {
if (!e.isTrusted) { e.preventDefault(); return;}
console.log('Button clicked!');
});
document.getElementById('btn1').click(); // nothing printed to console.
<button id="btn1">Button</button>

I would like to trigger a mouseup event, after it has been already triggered with exact same parameters

I would like to capture the event of a mouse up, and replay it exactly.
i am able to capture the old event mouseup event, put it inside the 'temp1' variable and try to re-trigger again.
$('#mycanvas').on("mouseup", function(e) {
window.temp1= e;
});
var evt = document.createEvent("MouseEvents");
evt.initEvent("mouseup", true, true);
document.getElementById("mycanvas").dispatchEvent(temp1);
I would like to replay the exact mouse up event but I get an error:
"VM39941:3 Uncaught TypeError: Failed to execute 'dispatchEvent' on
'EventTarget': parameter 1 is not of type 'Event'."
This is for a small tool of mine, I understand that what I am doing is nonstandard.
dispatchEvent() can only dispatch events that are created via Event() constructors. For this case, you can create a MouseEvent and copy over all of the relevant properties you need from the original event:
div.addEventListener('mouseup', function (event) {
console.log('moused up on div');
var evt = new MouseEvent('mouseup', {
altKey: event.altKey,
bubbles: event.bubbles,
cancelable: event.cancelable,
button: event.button,
buttons: event.buttons,
clientX: event.clientX,
clientY: event.clientY,
ctrlKey: event.ctrlKey,
detail: event.detail,
metaKey: event.metaKey,
relatedTarget: event.relatedTarget,
screenX: event.screenX,
screenY: event.screenY,
shiftKey: event.shiftKey,
type: event.type,
view: event.view
});
this.dispatchEvent(evt);
}, false);
<div id="div">Block 1</div>
n.b. you may be creating an infinite cycle of mouseup events.

MouseEvent does not propagate when creating it "manually" with MouseEvent constructor [duplicate]

My understanding of JS event propagation is that an event first "captures" down the DOM tree, then "bubbles" back up, triggering handlers along the way.
<html>
<body>
<div id="textbox">
nothing yet
</div>
</body>
<script>
// Gets incremented by "update" event
var val = 0;
// Event starts here
textbox = document.getElementById("textbox");
textbox.addEventListener("update", function(e) {
textbox.innerHTML = val;
}, false);
// Should bubble here
body = document.getElementsByTagName("body")[0];
body.addEventListener("update", function(e) {
val++;
}, false);
function update() {
var e = new Event("update");
textbox.dispatchEvent(e);
}
setInterval(update, 10);
</script>
</html>
In my code here there is a div "textbox" inside the body. I think the update event sent to the textbox should bubble up to the body, but it doesn't. The counter never updates.
If I set the UseCapture argument of the body's event listener to true, the counter updates.
Why does capturing work, but not bubbling?
dispatchEvent dispatches your event. Summarizing, that means
When an event is dispatched to an object that
participates in a tree (e.g. an element), it can reach
event listeners on that object's ancestors too.
First all object's ancestor event listeners whose
capture variable is set to true are invoked, in tree order.
Second, object's own event listeners are invoked.
And finally, and only if event's bubbles attribute value is
true, object's ancestor event listeners are invoked again,
but now in reverse tree order.
Therefore, if the bubbles attribute is not true, the event won't bubble.
You can set the bubbles attribute to true when you create the event with Event:
event = new Event(type [, eventInitDict])
Returns a new event whose type attribute value is set to
type. The optional eventInitDict argument allows for setting the bubbles and cancelable attributes via object members
of the same name.
To get the effect you want (show nothing yet, then 0,1,2,...) you need to follow a couple of the previous answers, plus set capturing on the textbox. (otherwise you'll see show nothing yet, 1, 2,...). First you need to set bubbling to true on your event - like this:
function update() {
var e = new Event("update",{bubbles:true});
textbox.dispatchEvent(e);
}
Then you need to capture the event (set to true) - like this:
// Event starts here
textbox = document.getElementById("textbox");
textbox.addEventListener("update", function(e) {
textbox.innerHTML = val;
}, true);
So everything looks like this:
// Event starts here
textbox = document.getElementById("textbox");
textbox.addEventListener("update", function(e) {
textbox.innerHTML = val;
}, true);
// Should bubble here
body = document.getElementsByTagName("body")[0];
body.addEventListener("update", function(e) {
val++;
console.log(val)
}, false);
function update() {
var e = new Event("update",{bubbles:true});
textbox.dispatchEvent(e);
}
setInterval(update, 1000);
You need to pass { bubbles: true } as the second argument to new Event( ... ) for the Event to bubble, as per the documentation on MDN, because bubbles defaults to false.
Updated jsfiddle example
If you use the old (unfortunately deprecated) way, it does bubble. See https://jsfiddle.net/py9vyr7h/1/
function update() {
var event = document.createEvent('CustomEvent');
// Second param says to bubble the event
event.initEvent('update', true, true);
textbox.dispatchEvent(event);
}

Programmatically click on a non-button element using javascript?

How to programmatically click on a non-button element using javascript? Or is it atleast possible in browsers like Firefox and Chrome?
Believe it or not, for a fairly basic click, you can just call click on it (but more below): Live Example | Live Source
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Artificial Click</title>
</head>
<body>
<div id="foo">xxxxxxx</div>
<script>
(function() {
var foo = document.getElementById("foo");
foo.addEventListener("click", function() {
display("Clicked");
}, false);
setTimeout(function() {
display("Artificial click:");
foo.click(); // <==================== The artificial click
}, 500);
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
})();
</script>
</body>
</html>
You can also create the relevant type of Event object and use dispatchEvent to send it to the element:
var e = new MouseEvent("click", {
view: window,
bubbles: true,
cancelable: true
});
foo.dispatchEvent(e);
This gives you the opportunity to do things like set other information (the typical pageX and pageY, for instance) on the event you're simulating.
More about the various event object types in Section 5 of the DOM Events spec.
You can use HTMLElementObject.click()
Something like document.getElementById('div1').click()
See more
Or in jQuery (documentation) to click on a non-button element
$( "#nonButton" ).click();
or to listen for a click on that non-button element
$("#nonButton").on("click", doSomething);
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
document.getElementById("nonButton").dispatchEvent(evt);
see: https://developer.mozilla.org/en-US/docs/Web/API/event.initMouseEvent
document.querySelectorAll('#front-chat-container div[role]')[0].click()
worked for me - to click a div element.

Detect if button click real user or triggered by a script

Is there any method that enables me to detect whether a button click was performed by a real user and not some automated method (javascript) that a user has loaded onto their browser developer console or other browser developer tool?
I tried the following methods suggested in various stackoverflow posts but none of them appear to work.
REF: How to detect if a click() is a mouse click or triggered by some code?
Script Detection methods tried and failed:
mybutton.click(function (e) {
if (!e.which) {
//Triggered by code NOT Actually clicked
alert(' e.which - not a real button click')
} else if ('isTrusted' in e && !e.isTrsuted) {
//Triggered by code NOT Actually clicked
alert(' e.isTrusted - not a real button click')
} else if (e.originalEvent === undefined) {
//Triggered by code NOT Actually clicked
alert(' e.originalEvent - not a realbutton click')
}
// else if (!e.focus) {
// //triggered // does not detect e.focus on a real btn click
// alert(' e.focus - not a realbutton click')
// }
else {
// Button hopefully clicked by a real user and not a script
}
})
If I run the following script to trigger the button click from the Chrome browser console none of the methods above traps it as being triggered by a script.
var button = document.getElementById("btnSubmit");
button.click();
==========================================================================
Thank you for all your responses and thanks to stackoverflow for providing such a great site that facilitates so much knowledge sharing and for saving us techies an untold number of hours.
It appears that I still do not have reliable method. All 3 browsers (FF, IE & Chrome) provide a developer/console interfaces for a user to run/inject a javascript on my webpage. It appears that each browser flavor traps some event property values a little differently. For example: Chrome traps the difference between a script activated cick and a real user with e.screenX but in IE: e.screenX has the same value for both a script click (synthetic) and a user button click
The following detection methods either did not work at all or are inconsistent across the different browsers: e.which e.isTrsuted e.originalEvent (event.source != window) (e.distance != null)
The mousedown event appears to be only triggered by a real user button click, but I have to assume there is some script method to emulate a mousedown in addition to a button click event
$(me.container + ' .mybutton').mousedown(function (e) {
alert('mouseisdown real button click');
}
If anyone can figure out a reliable method that works across multiple browsers, that detects the difference between a synthetic (script) button click and a button click by a user, you will deserve superhero status.
when a button click happens through the mouse, the event e usually has the mouse pointer location recorded. Try something like :
if(e.screenX && e.screenX != 0 && e.screenY && e.screenY != 0){
alert("real button click");
}
No, it's not possible in all cases.
As other answers mentioned, you can look for the mouse coordinates (clientX/Y and screenX/Y), and if they're not present, you can assume it was probably not a human-generated action.
But, if the user tabs onto the button and uses the space bar to click it, or otherwise clicks it without using a mouse, the coordinates will also be zero, and this method will incorrectly determine it to be a scripted click.
Also, if the script uses dispatchEvent instead of click, coordinates can be given to the event. In this case, this method will incorrectly identify it as a user-generated click.
// This will produce what appears to be a user-generated click.
function simulateClick(element) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window,
0, 110, 111, 10, 11, false, false, false, false, 0, null);
element.dispatchEvent(evt);
}
http://jsfiddle.net/bYq7m/
For security purposes when you trigger an event with javascript it will register differently than if the user triggered the event. Console log the ev object and you will see significant differences between the two cases.
mybutton.click(function(ev) {
console.log(ev);
});
Here are some sample output of the two cases:
jQuery.Event
currentTarget: button
data: null
delegateTarget: button
handleObj: Object
isTrigger: true
jQuery191011352501437067986: true
namespace: ""
namespace_re: null
result: undefined
target: button
timeStamp: 1360472753601
type: "mousedown"
__proto__: Object
jQuery.Event {originalEvent: MouseEvent, type: "mousedown", isDefaultPrevented: function, timeStamp: 1360472840714, jQuery191011352501437067986: true…}
altKey: false
bubbles: true
button: 0
buttons: undefined
cancelable: true
clientX: 39
clientY: 13
ctrlKey: false
currentTarget: button
data: null
delegateTarget: button
eventPhase: 2
fromElement: null
handleObj: Object
isDefaultPrevented: function returnFalse() {
jQuery191011352501437067986: true
metaKey: false
offsetX: 37
offsetY: 11
originalEvent: MouseEvent
pageX: 39
pageY: 13
relatedTarget: null
screenX: 1354
screenY: 286
shiftKey: false
target: button
timeStamp: 1360472840714
toElement: button
type: "mousedown"
view: Window
which: 1
__proto__: Object
Use "event.isTrusted" to know event is triggered from Javascript or User click.
Sample Code:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<input type="text" id="myInput">
<button id="myBtn" onclick="callFunction(event)">Click Me</button>
<script>
function callFunction(event) {
console.log(event.isTrusted); // true only when user clicks 'Click Me' button
}
window.onload = function () {
let event = new Event("click");
callFunction(event); // false
}
var input = document.getElementById("myInput");
// Execute a function when the user releases a key on the keyboard
input.addEventListener("keyup", function (event) {
if (event.keyCode === 13) {
event.preventDefault();
document.getElementById("myBtn").click(); // false
}
});
</script>
</body>
</html>
Fiddle Here.
$("button").mousedown( function(e) {
if(e.which) {
alert(1);
}
});
$("button").trigger("mousedown");
Or Javascript:
document.getElementsByTagName('button')[0].onmousedown = function(e) {
if(e.which) {
alert(1); // original click
}
}
document.getElementsByTagName('button')[0].onmousedown();
You can see in the fiddle, it will not let trigger function to call but only when mouse is down on button. If automated click is triggered on button then e.which is undefined which can be trapped easily.
UPDATE : Fiddle For Javascript
Event object have a nativeEvent object which contains isTrusted field.
Its value will be false when event is not triggered by real user.
So you can check if real user clicked the button by -
if(event.nativeEvent.isTrusted){
//Real user
} else {
//Triggered by script
}

Categories