When clicking the colored boxes on this MDN example page, the URL shows the coordinates of the click.
When using document.querySelector("input").click(), the URL shows coordinates of x=0&y=0.
I want to programmatically click the button, using the console or a userscript, such that the URL shows the coordinates I specify.
What I’ve tried:
document.querySelector("input").dispatchEvent(new MouseEvent("click", {
x: 55, // And also `offsetX` and `clientX`.
y: 55
}));
The documentation on MouseEvent notes that these don’t actually move the cursor, which is fine.
I tried putting a <div> over it, passing the click through.
const newdiv = document.createElement("div");
newdiv.style.position = "fixed";
newdiv.style.height = "1px";
newdiv.style.width = "1px";
newdiv.style.top = "55px";
newdiv.style.left = "55px";
newdiv.style.pointerEvents = "none";
document.querySelector("div").prepend(newdiv);
newdiv.click();
This works for manual clicks, but .click() doesn’t do anything (because it’s a sibling?).
document.querySelector("input").prepend(newdiv); will bubble, but it’s still (0, 0).
How can I click at a coordinate?
I had already tried the answers of the suggested question How to simulate a click by using x,y coordinates in JavaScript? before asking this question (it was one of the first Google results I found). This question is not a duplicate because the marked answer, firstly gets the element, then clicks it:
document.elementFromPoint(x, y).click();
which is exactly the same as
document.querySelector("input").click();
Comments suggest this is not possible, because it could make users click ads. Can it truly not be done?
Other solutions “click” the page / element, but do not submit the form (the URL does not change to show where the button was clicked).
It seems that setting the coordinates on the <form> when submitting via <input type="image"> only happens for user-initiated events and not for synthetic events.
However, it’s possible to emulate the behavior by other means.
When a form is submitted via <input type="image">, the request has two more query fields (or form data fields), x and y, representing the clicked coordinate.
But if the input has a name attribute, both coordinates are prefixed by the value of the name attribute and a ..
We can define a function to submit a form with specified coordinates based on a given <input type="image"> and call it.
The function basically needs to insert two <input type="hidden"> elements with the correct name and value properties.
Upon form submission, these two fields are taken into account, automatically.
Here’s a demonstration of this function in action.
const submitViaImage = (() => {
const insertedElements = new WeakMap();
return (button, x, y) => {
if(button.form){
if(insertedElements.has(button.form)){
Array.from(insertedElements.get(button.form))
.forEach((element) => element.remove());
}
else{
insertedElements.set(button.form, new Set());
}
const prefix = (button.name
? `${button.name}.`
: ""),
hiddenX = Object.assign(document.createElement("input"), {
name: `${prefix}x`,
type: "hidden",
value: x
}),
hiddenY = Object.assign(document.createElement("input"), {
name: `${prefix}y`,
type: "hidden",
value: y
});
insertedElements.get(button.form)
.add(hiddenX)
.add(hiddenY);
button.form.append(hiddenX, hiddenY);
button.form.submit();
}
};
})();
// Here, some event is bound to something that submits the form,
// just demonstrating how to use the function above.
const target = document.querySelector("input[name='last']");
document.getElementById("somethingThatSubmitsTheForm")
.addEventListener("click", () => submitViaImage(target, 40, 60));
<form>
<label>Some other data: <input name="someData" type="text"></label>
<div>
Submit:
<input name="first" type="image" src="//picsum.photos/100?1">
<input name="last" type="image" src="//picsum.photos/100?2">
</div>
</form>
<input id="somethingThatSubmitsTheForm" type="button" value="Click here to submit the form via the second image at (40, 60).">
After clicking any of the buttons, you can inspect the iframe of the Stack Snippet to verify that its internal documentURI is indeed set to the expected URL with the someData, first.x or last.x, first.y or last.y fields.
Unfortunately, the form really needs to be directly submitted via .submit(); it’s not really possible to delegate submission via button.click() because this will attempt to overwrite the x and y coordinates resulting in something like ?last.x=0&last.y=0&last.x=40&last.y=60.
However, button.click() is preferred when you expect form submission to be handled by an event listener with preventDefault called.
The x and y coordinates are not set in this case, but it correctly sets the submitter of the SubmitEvent among other things.
The function closes over a WeakSet called insertedElements.
This is used to keep track of the elements added to any <form> so they can be removed before adding new ones.
Otherwise, more and more hidden inputs get added to the <form>s which will all be part of the submitted form data, containing obsolete data.
The inserted elements will be gone once the page reloads after form submission, but it’s still theoretically possible to load the submission response somewhere else, which is why removing the elements is still important.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With