Emulating middle click on element with an "onclick" event - javascript

The Problem
For site testing, I am attempting to emulate a middle click (or scroll wheel click) on an element like the one below, using JS that is based on some other answers on here.
HTML:
<a
id="example-link" href="https://www.google.com/"
target="_blank"
onclick="window.open('https://www.google.com/', '',
'width=500, height=500, resizable=1, scrollbars=1');
return false;">
<span>Middle Click Me</span>
</a>
JS (looking to change something here):
var middleClick = new MouseEvent( "click", { "button": 1, "which": 2 });
jQuery("#example-link")[0].dispatchEvent( middleClick );
The issue is shown in this jsfiddle.
Note that a regular click should normally dispatch a popup. jsfiddle is catching the popup and opening it in a new tab.
jsFiddle is used instead of a stackoverflow fiddle to avoid confusion, as the stack overflow fiddle doesn't properly handle window.open().
Compare 1) middle-clicking manually to 2) running the code to emulate a click.
The problem is, when I trigger the middle click programmatically, it triggers both the onclick method of opening a new window, as well as opening the link in a new tab (creating both a popup and a tab instead of just a tab). If this link is middle clicked manually, the popup will not trigger.
The Question
Is there a better way of emulating middle clicks (preferably cross-browser compatible)? The way it is written, I can't really get the MouseEvent script to accurately emulate manual middle clicks.
Edit: unfortunately, I can't change the HTML object or modify the DOM for the purpose of testing integrity, so I would prefer that the onclick tag stays on the element.

To the best of my understanding, as long as that inline click handler is there, it will fire on every click event on that element, but here are two workarounds I've come up with.
If you really can't modify the DOM even for an instant, then the first option won't serve. It cheats by changing the DOM and then restoring it, hopefully before anyone notices.
The second option avoids the need to click the link at all by reading its attributes and using them to open a new tab, without firing a new click event. (This relies on the script having a basic understanding of link element's markup. Specifically, the code I've written here simply assumes that the "link" element has a valid url in its href attribute -- but if necessary, you could make other, more complex assumptions, and act conditionally based on the properties that the "link" element turns out to have at runtime.)
Note: A third alternative would be create a custom event that has all the same core behavior as the built-in click event but without actually being a click event, the idea being to fool the onclick handler into sleeping through the event. I'm not sure how much work it would take to do a sufficiently good job of rebuilding this particular wheel. Maybe it wouldn't be too bad?
In this script, the functions that open the new tab are triggered by button clicks, but of course this is just for demo purposes, and you'd presumably trigger them on page load or as callbacks to some other action. And the anchor element in the snippet has been changed slightly, too, for space-saving reasons
.
(Because the direct call to window.open doesn't appear to work properly in the Stack Overflow snippet, I followed your lead and pasted the code into a fiddle so it can be seen running in all its nominal glory.)
const
// Identifies some DOM elements
cheatButton = document.getElementById("cheat-button"),
mimicButton = document.getElementById("mimic-button"),
exampleLink = document.getElementById("example-link"),
// Defines an event to be dispatched programmatically
middleClick = new MouseEvent("click", {button: 1, which: 2});
// Demonstrates calling the functions
cheatButton.addEventListener("click", emulateMiddleClick); // Option 1
mimicButton.addEventListener("click", followLink); // Option 2
// Defines the functions
function emulateMiddleClick(){
const onclickHandler = exampleLink.onclick; // Remembers onclick handler
exampleLink.onclick = ""; // Supresses onclick handler
exampleLink.dispatchEvent(middleClick); // Dispatches middle click
exampleLink.onclick = onclickHandler; // Restores onclick handler
}
function followLink(){
if(!exampleLink.href){ return; } // In case href attribute is not set
const {href, target} = exampleLink; // Gets props by using "destructuring"
// This doesn't seem to work in the Stack Overflow snippet...
window.open(href, (target || "_blank")); // In case target attribute is not set
// ...But we can at least log our intention to open a new tab
console.log(`opening: "${href}" (in "${target}")`);
}
div{ margin: 1em; }
button{ padding: 0.3em; border-radius: 0.5em; }
span{ margin: 1.3em; }
<div>
<button id="cheat-button">Fake Click, and Suppress Handler</button>
</div>
<div>
<button id="mimic-button">Follow Link without Clicking</button>
</div>
<a id="example-link"
href="https://www.google.com/"
target="_blank"
onclick="window.open('https://www.google.com/', '', 'width=50, height=50');">
<span>Middle Click Me</span>
</a>

Related

Adding custom event to programatically open contextmenu

As said in the title, I am trying to customize the contextmenu event. The situation is this: I want to catch the event, preventing it from firing on some elements (I'm ok here, all good), then I want to call it targeting another element (this is not working). At first I just tried dispatching it by creating a custom event and using myTargetElement.dispatchEvent(), the custom element does fire, but context menu won't open.
The reason I need this is that I want to open the contenteditable context menu when the user clicks anywhere. I've tried something similar to the last example on this MDN page, and I logged the event type, it is firing. Here's some example code of what I'm doing.
HTML
<div id="prevent">This div will prevent default event behaviour.</div>
<div id="my-target" contenteditable>Fire here the event and open context menu</div>
For instance, I cannot put one div inside the other.
JS
function showMenu(){
const preventer = document.getElementById('prevent');
const myTarget = document.getElementById('my-target');
const myEvent = new Event('contextmenu', {
bubbles:false //I had to use this, as setting it true was logging an error on Firefox
});
myTarget.dispatchEvent(myEvent);
console.log(myEvent.type); //it does log the event name
}
The listener that prevents default is not important, as when I just run the showMenu() (even when removing every other bit of js) on console it still has not the intended effect. I'm also able to listen to the 'contextmenu' event when I add a listener and run showMenu().
I'm beginning to think that there is not a direct solution to this, but workarounds and ideas would be really appreciated.

Trigger native browser behavior for (middle) click on a link

Question
I want to trigger a (middle) mouse click on a link, in a way that triggers the native browser behavior for this event.
E.g. in those browsers I work with, middle-click will cause the linked page to open in a new tab in the background.
But if other browsers have a different behavior, that should be triggered instead.
I know there is the element.click(); method, but how do I tell it which mouse button should be clicked?
Background
The background is that I want to make a div behave as much as possible like a regular link. The idea was that I would create a hidden link tag and trigger the native browser behavior.
Requirements for the div-as-a-link:
href can come from a data-href attribute.
Native browser behavior for left-click, middle-click and possibly right-click.
respect of the target attribute, which could come from a data-target attribute.
tabindex
activation with the keyboard?
possibility to select text snippets within the div. This means we cannot just use an overlay.
Why not use a native link tag? Because the div contains inner <a> tags. So making the div box an a-tag would cause nested a-tags which would cause some browsers to restructure the DOM tree.
Obviously I could just set document.location.href on click. But this is only 20% of the browser's native behavior.
I could also try to detect the mouse button, and use js to open the tab in the background, if it was the middle button.
But maybe some browsers have a different behavior for middle-click. I would rather let the browser do its thing, than trying to replicate a specific browser behavior with js.
The idea I had was to create a hidden <a> tag with the same href, and delegate click events from the <div> to this hidden <a> tag. For this, I need to trigger the event with the same mouse button. I am not sure how to do this.
js or jQuery?
jQuery is ok for my personal use case. But to make this useful to a wider audience, maybe also post how to do it without jQuery, if you know.
See also
There are some question which deal with this kind of problem, but each of them looks at a different angle or has different constraints.
This is what I come up with thanks to #JonUleis in the comments and #MikeWillis in https://stackoverflow.com/a/32868971/246724
$('.linkbox', context).once('linkbox').each(function(e){
var $linkbox = $(this);
var href = $linkbox.data('href');
if (!href) {
return;
}
var $hiddenLink = $('<a>').attr('href', href).hide().appendTo('body');
$linkbox.click(function(e){
$hiddenLink[0].dispatchEvent(new MouseEvent('click', {button: e.button, which: e.which}));
e.preventDefault();
});
});
Note that I put the hidden link outside of the clicked div, to prevent recursion.
The right-click menu does not give me "copy link url", but I imagine this would be really hard to replicate.
UPDATE: I found that I don't really need to append the link to anything, and it still works. But I only tested this in Chromium on Linux so far.
This is the code to achieve left click and middle click functionality.
tabindex works with any html element so you can use it not the div
$("#link").on('click', function(e) {
const hasTargetBlank = $(this).data('target') === '_blank';
const href = $(this).data('href');
switch(e.which) {
// left click
case 1: {
if (hasTargetBlank) {
window.open(href);
} else {
window.location = href;
}
break;
}
// middle click
case 2: {
window.open(href);
break;
}
// right click
case 3: {
// do what you want to do
}
}
});

how to stop refreshing parent page while child window open?

when i click link to open child window, parent page refresh automatically. how can i stop it?
parent page should not refresh while open child window. how to do this? please help me.
my code is as below given:
<html>
<head>
<title>login</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script type="text/javascript">
var popup;
function ShowPopup(url) {
if(popup)
{
popup.close();
}
popup = window.open(url, "self", "toolbar=no,scrollbars=yes,location=no,statusbar=no,menubar=no,resizable=0,width=300,height=350,left = 0,top = 0");
popup.focus();
}
</script>
</head>
<body>
Sign In / Register
</body>
</html>
Your page refreshes because not only is your function called, but also the
hyperlink indicated by the a tag is executed. So you have two things happening
at the same time:
the hyperlink itself navigates to whatever is in the href attribute,
even if it is empty. If href is empty it means: reload this page.
the onclick event handler also does something (opening a popup), but it
does currently not cancel the first effect.
In a first reaction one might just remove the offending href
attribute. This solves the problem, but introduces another: you lose all the nice
styling on the displayed hyperlink text (like underline, color, changing cursor, tab order, ...),
which is generally not what you want.
Here are some more convenient solutions:
Let the onclick event handler return false
Returning false will cancel the anchor's default behaviour and the content of the href attribute will be ignored:
onclick="ShowPopup('popup_login.asp'); return false;"
If you care about browsers that have no javascript support (or have it disabled), then put
a meaningful fall-back url in the href attribute, like:
href="javascript_is_required.html"
Use event.preventDefault
This is an alternative to return false. It has the advantage that you can make it
execute as the first instruction, so that if a run-time error occurs in the other code
it will already have done it's job:
onclick="event.preventDefault();ShowPopup('popup_login.asp');"
Note that this event object is defined by all browsers in the context of event attributes,
and is to be distinguished from the window.event object, which is not supported by
all browsers.
Use hash notation in href
Give the anchor a name
and then reference that name in the href attribute. This way
the anchor will navigate itself into view, which
it usually already is when the user clicked it:
name="loginlink" href="#loginlink"
You will often see the shorter variation href="#", but this will scroll the page to the top
when clicked, which might be OK if you know for sure the page is not scrolled down.
Still, the use of "#" has a side-effect: when clicked the url changes and the
previous url is put on the browser's history stack. So if after clicking the link you press the back button,
you stay on the page. This may be undesired.
Use the javascript: protocol to do nothing
href="javascript:"
This will make the hyperlink execute any javascript following the colon, and since there
is none there, nothing will happen. The browser history is not modified. There are variations
to this method, like javascript: return false; or javascript: void(0);
Use the javascript: protocol to handle the click event
With this solution you no longer use the onclick attribute. Instead you move the code
to the href attribute:
href="javascript: ShowPopup('popup_login.asp');"
Separation of lay-out and code
The original code and all the above solutions still have an issue that many developers
do not like: HTML is mixed with javascript code. It is better to separate these two.
This can be done as follows:
<a href="javascript_is_required.html" id="loginLink"
title="Click here to log on"> ... </a>
...
<script>
document.getElementById('mylink').onclick = function(e) {
e = e || event; // cross-browser way to get event object
e.preventDefault(); // cancel the default click behaviour
ShowPopup('popup_login.asp'); // your custom code comes here
return false; // cancel the default click behaviour
};
</script>
A few will say this also
has a down-side: it is harder to identify the code that executes on a click.
The above code will attach the event handler to the click event of the mylink
element. Make sure to have it execute only after the document has loaded.
The event handler cancels the default click
behaviour in two ways. Choose the one you prefer, or both if you want. As it is
cancelled, the navigation to the href attribute value is never executed. The first
line deals with browser specifics as older IE browsers do not pass the event object
as an argument to the event handler, but expose a global event object instead.
If you don't have to support pre-IE9 browsers, you can improve more by using
addEventListener('click', myfunction); instead of onclick = myfunction; in the
above code. This has many advantages: more event handlers can be attached to the same
event, and you can also remove them one by one. jQuery offers good cross browser support
for this with .on().
There are several variations on the above solutions, all with their
benefits and downsides. You could even step away from using an anchor for this purpose
and use another element instead with styling added to it.
Write return false(); after the window.open() JS method.
In case the above snippet is not working, change the default <button> tag to normal <input> tag with type="button". This will solve the problem.
Below is the code snippet:
JavaScript
<script>
function tagedlist() {
window.open("http://w3schools.com","mywindow","menubar=1,resizable=1,width=1000,height=1000");
return false;
}
</script>
Just adding type="button" in <button> tag worked. I know it's redundant but it worked!
From this:
<button id="btnDeleteRequest" class="btn btn-default" accesskey="D" onclick="ExecuteCommand('DeleteRequest',this);">
To this:
<button id="btnDeleteRequest" class="btn btn-default" type="button" accesskey="D" onclick="ExecuteCommand('DeleteRequest',this);">
I had button something like this
html:
<button onclick="captcha()" >Verify Human</button>
js:
function captcha(){
window.open(link,name,"width=800, height=600");
return false;
}
After adding type="button" in html content it worked
<button onclick="captcha()" type="button">Verify Human</button>
I know its redundant but it works ;)
Also thanks to #sojim

JavaScript Click event fires via the Enter Key but not via the Mouse

Some code that looks like the following is firing the click event via the Enter key, but is not responding to the mouse click.
//a is an anchor element
a.addEventListener('click', function (e)
{
//Do Stuff...
});
This page demonstrates the problem. The relevant bit of code is at line 176. This is in the middle of development and currently only (sort of) works in Chrome.
Also, I just verified that it works if I use mousedown, so it's not just the case of an invisible element sitting in front of the anchor.
Any ideas?
Edit: Now that you've shown us the actual code you're using, the problem is related to the fact that the autoSuggest() function has it's own click handler and in that click handler, it is clearing the container which removes all <a> elements in the container so your link object gets destroyed (probably before your click event gets to process). So, you can get events that happen before the click (like mousedown), but after a click, the element is removed from the DOM.
If you tell us what you're trying to actually do when an auto-suggest item is clicked that is different than the default behavior of the autoSuggest() function and you point to any documentation for that function, then perhaps we could offer a better way to solve your issue.
The link may be firing and taking you off to a new page (or reloading the current page), thus preventing you from seeing the click code run. Usually when you process a click event on a link element, you need to prevent the default behavior:
//a is an anchor element
a.addEventListener('click', function (e) {
e.preventDefault();
//Do Stuff...
});
Another possibility is that you are trying to install the event handler too soon either before the DOM has been loaded or before this particular link has been created and thus no actual click event handler is attached to the DOM object. You can verify whether the event handler is even getting called by temporarily putting an alert("Click handler called"); in the event handler and see if that pops up or not.

Mobile Safari Event Issue

I have designed a website with a menu that is initially invisible. When the user clicks on a button, the menu becomes visible. There are two ways for the user to hide the now visible menu:
Click the button that caused the menu to become visible
Click anywhere on the web page that isn't the menu
The way I have coded the second option is to tie an onclick event to the window element, and have it compare where the user clicked to the menu's position to determine if the menu should be hidden. This works great in Firefox and Safari, but it fails in Mobile Safari.
I noticed that the window onclick event only fires when I click on another element with an onclick event already assigned. If I click on an element with no event(s) assigned, the window's onclick event never fires. If I click on the button which displays the menu, it fires along with the event tied to the button.
Is it possible to assign events to the window element in Mobile Safari?
I'v been encountering this same problem. Here is what worked for me. (Note: I am working within a Modernizr and jQuery context)
First, I add a custom Modernizr class using Modernizr's addTest Plugin API to test for iOS, which will add the class appleios or no-appleios accordingly.
Because in my research the body seems to fire events on it's own agenda, I am taking a little precaution by wrapping all the document's content with an element in an iOS context. Then I add an event handler to this element.
$(".appleios body").wrapInner('<div id="appleios-helper" />');
$("#appleios-helper").bind("mouseup", function(){return;});
What was suggested earlier in this thread is using void(0). I did some quick testing, and found that void(0) as the event just wasn't causing touches on the body to be recognized. When I plugged in my own "empty" function in the form of function(){return;} things started working.
This all hinges on the fact that no events are fired in Mobile Safari unless the element explicitly has events to fire (Safari Web Content Guide.) By inserting this empty event on the wrapper, things will bubble up to the body.
If you're doing strait JavaScript with none of these libraries, the same effect could be achieved in the HTML markup
<html>
...
<body>
<div id="appleios-helper" onmouseup="function(){return;}">
...
</div>
</body>
</html>
This worked for me to hide tooltips when touching anywhere on the document's body. Your mileage may vary.
Simply adding the dummy onclick handler to the html body works for me:
<body onclick="void(0)">
Note that I am using usual live event handlers as shown below:
function liveHandler( event ) {
var target = event.target; ...}
window.addEventListener(evtype, liveHandler, true);
// evtype such as 'mousedown' or 'click'
// we use the capturing mode here (third parameter true)
This is an old question, but I struggled with the same thing today.
I found that using touchstart event works.
I solved it like this:
var isTouchDevice = 'ontouchstart' in document.documentElement;
if (isTouchDevice) {
// Do touch related stuff
$(document).on('touchstart', function (event) {
// Do stuff
});
} else {
// Do non-touch related stuff
$(document).on('click', function () {
// Do stuff
});
}
You could just add onclick="void(0);" to some <div> that covers the whole page so that no matter what, you are always clicking on an element that has an onclick event. Not a great solution, though.
I'd prefer not having the onclick event be tied to the window. Why don't you create a container <div> that has that event on it. Then handle it just like you currently are.
You can also:
$('body').css('cursor', 'pointer');
No idea what those "engineers" at Apple are doing. LOL.
This has problems though. You wouldn't want to do this on every touch device. Only touch devices that don't also have a pointing device (Laptops with Touch Screens, for example).
Source: http://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
The conclusion of the article is this:
So I don’t understand why all this is the case, but it most certainly is the case. If you’re having bubbling problems, just add an empty-function event handler anywhere between the body and the element, and you’re set to go. But it shouldn’t be necessary.

Categories

Resources