the problem I've encountered is documented here.
window.open behaviour in chrome tabs/windows
where you can not open multiple windows via javascript in chrome.
I would like to open the multiple windows if it is supported, if it is not supported I will simply return a list of links.
is there a way using modernizr or something besides browser sniffing that I can determine if the behavior is supported?
This ability to open multiple windows various widely between browser and even by browser config.
So never assume you will be able to open multiple pop ups, you might be able to, but you can only know by testing, it's very easy to test tough.
To test if opening a pop up succeeded, inspect the return value.
var popupWindow = window.open('http://www.google.com/');
if (!popupWindow) {
console.log('the window did not open');
// do other stuff
}
If the window opened the return value will be a Window object.
If the the window did not open, the return value will be be falsy, this exact return value can vary from pop up blocker to pop up blocker, but generally you can assume the value to be falsy if the window did not open; meaning undefined or null.
As such it's very easy to trigger an alternate method in case the window failed to open.
You do not need modernizr or any plugins for this, this behavior of returning the Window object is the same in all browsers.
MDN reference:
https://developer.mozilla.org/en-US/docs/Web/API/Window/open
Firefox and Safari seem to support opening multiple windows by default. Chrome however will block the second window and show the little "pop up" blocked message.
Additionally Chrome will also block opening windows that did not originate from direct users actions; meaning a click or a key press.
Nothing like modernizr or any custom code is going to give you any type of feature detection. The main reason is because all major browsers require some sort of user action to open a new window programmatically - usually a click. So creating a feature detection is out of the question.
This is an interesting question and one where thinking in terms of "progressive enhancement" might help you get to a good solution.
First, let's assume that you cannot open multiple windows in any browser. What would you do? Show a list of links as you've suggested. By adding something like target="_blank" to each link, now we have a working app without any JavaScript (or if the user has JavaScript disabled):
<section id="links-wrap">
<a href="/page-A.html" target="_blank" />
<a href="/page-B.html" target="_blank" />
</section>
This baseline of functionality will work on every single browser ever made - your Treo visitors will love you. However, this experience is less than ideal because the links are likely to open new tabs instead of new windows. So let's use JavaScript to open a new window whenever a link is clicked. Lets also hide each link after it is clicked and position each window so that they are not overlapping:
function openWindowFromLink (link, idx) {
var top = idx % 2 * 600;
var left = Math.floor(idx/2) * 600;
var win = window.open(link.href, 'Window '+ top +'x'+ left, 'width=600,height=600,top='+ top +',left='+ left);
if (win) {
link.style.display = "none";
}
return win;
}
function handleLinkClick(ev) {
ev.preventDefault();
var link = ev.target;
var idx = 0;
var prev = link.previousSibling;
while (prev) {
if (prev.nodeType === 1) {
idx++;
}
prev = prev.previousSibling;
}
openWindowFromLink(link, idx);
}
document.getElementById('links-wrap').addEventListener('click', handleLinkClick);
Now comes the hard part: how can we open many windows at once. As we know, Chrome will only allow one window to open per user click. While other browsers might not have this same restriction, they may add it in the future (I'm actually surprised that they don't all have this restriction right now). So lets assume that all browsers have the same limitation as Chrome. Users don't want to click every single link every time - so lets give them a click target that they can click really fast to open all of the windows. Creative wording will reduce the annoyance of this task.
<div id="rapid-click-box">
Click me really fast and see what happens!
</div>
... and some JavaScript:
var clickBox = document.getElementById('rapid-click-box');
var clickCount = 0;
clickBox.addEventListener('click', function handleRapidClick (ev) {
var link = links[clickCount];
if (link.style.display !== 'none') {
openWindowFromLink(link, clickCount);
}
if (++clickCount === links.length) {
clickBox.removeEventListener('click', handleRapidClick);
clickBox.style.display = 'none';
}
});
Finally, lets take care of those browser which allow multiple windows to be opened at once. We still need the user to click in order to call window.open - so lets get creative and see how we can make the user click something. A cleverly worded welcome message should suffice:
<div id="welcome-message" style="display:none">
<h1>Hey, welcome to my site. Are you a human?</h1>
<button>Yes</button>
</div>
<script>
// show the welcome message immediately if JS is enabled
document.getElementById('welcome-message').style.display = 'block';
</script>
... and once again, a little bit of JavaScript:
var button = document.getElementsByTagName('button')[0];
button.addEventListener('click', function handleYesClick (ev) {
ev.preventDefault();
button.removeEventListener('click', handleYesClick);
document.getElementById('welcome-message').style.display = 'none';
for (var i = 0, l = links.length; i < l; i++) {
if ( !openWindowFromLink(links[i], i) ) {
break;
}
}
if (i === links.length) {
clickBox.style.display = 'none';
}
});
And a fiddle to show it all in action:
https://jsfiddle.net/q8x5pqsw/
Related
To improve performance on some bulky web apps, I've created an update that converts them to single-page apps. Only JS / jQuery are in use; thus far, it hasn't seemed useful to introduce Angular, React, Meteor, etc. However, beta testing has revealed a problem, which is that (duh) sometimes a user will want to open something in a new tab / window. The interactive elements in question are currently anchors with no href attribute, so it is not currently possible to open in a new tab.
My understanding is that if I were to use an a with an href and preventDefault(), users would still not be able to open in a new tab.
I considered placing "open in new tab" checkboxes next to the interactive elements, and I considered some other approaches that would require people to learn new, idiomatic interaction patterns. Bad idea.
Now, I'm thinking that I'll try using the onbeforeunload event handler to prevent changing the current window's location and instead affect the desired changes to the current screen. I believe this would not prevent opening in a new tab, since doing opening in a new tab won't fire the unload event.
I can't be the first person to try to address this problem, but I can't find any info on it, either. Anyone know how to prevent opening in the same tab while allowing opening in a new tab and while not forcing people to learn new interaction patterns? Anyone have a reason to believe that using the onbeforeunload event handler will not allow me to achieve that?
Update
In case it helps anyone in the future, below is what I developed. Thanks to #Kiko Garcia; it hadn't occurred to me that one could detect which mouse button was used. Tested on Firefox 54, Chrome 57, Edge, IE 11 (all on Windows 10) and on Safari for iOS10 and on Android Browser for Android 7. (Will test on Mac next week, but assuming it's good for now.)
// track whether or not the Control key is being pressed
var controlKeyIsPressed = 0;
$(document).keydown(function(keyDownEvent) {
if(keyDownEvent.which == "17") {
controlKeyIsPressed = 1;
}
});
$(document).keyup(function(){
controlKeyIsPressed = 0;
});
// on clicking anchors of the specified type
$("a.some-class").on("click", function(clickEvent) {
// left click only
if (clickEvent.which == 1 && controlKeyIsPressed == 0) {
// prevent default behaviour
clickEvent.preventDefault();
// perform desired changes on this screen
// middle click
} else if (clickEvent.which == 2) {
// prevent default behaviour because behaviour seems to be inconsistent
clickEvent.preventDefault();
}
});
Just as this answer says you can just provide different actions for different mouse events. Of course that can be an window.open() or a location.href change, for example.
With that you can do something like:
left click: change location.href
middle click: open new window
right click: open your custom menu
$(document).mousedown(function(e){
switch(e.which)
{
case 1:
//left Click
break;
case 2:
//middle Click
break;
case 3:
//right Click
break;
}
return true;// to allow the browser to know that we handled it.
});
Try that
Please note that I just pasted the answer's code. You should adapt to your tagname and usability
I came across this in some JS code I was working on:
if ( typeof( e.isTrigger ) == 'undefined' ) {
// do some stuff
}
This seems to be part of jQuery. As far as I can see it tells you if an event originated with the user or automatically.
Is this right? And given that it's not documented, is there a way of finding such things out without going behind the curtain of the jQuery API?
In jQuery 1.7.2 (unminified) line 3148 contains event.isTrigger = true; nested within the trigger function. So yes, you are correct - this is only flagged when you use .trigger() and is used internally to determine how to handle events.
If you look at jQuery github project, inside trigger.js file line 49 (link here) you can find how isTrigger gets calculated.
If you add a trigger in your JavaScript and debug through, You can see how the breakpoint reaches this codeline (checked in jQuery-2.1.3.js for this SO question)
Modern browsers fight against popup windows opened by automated scripts, not real users clicks. If you don't mind promptly opening and closing a window for a real user click and showing a blocked popup window warning for an automated click then you may use this way:
button.onclick = (ev) => {
// Window will be shortly shown and closed for a real user click.
// For automated clicks a blocked popup warning will be shown.
const w = window.open();
if (w) {
w.close();
console.log('Real user clicked the button.');
return;
}
console.log('Automated click detected.');
};
I am working on a site that provides the user with quotes and reservations for rental equipment. If the user gets more than a few steps into the processes and chooses to close the browser or navigate away before finishing then the client would like to offer then a special deal. The client would like to prevent the window from closing and ask them for their phone number so they can call them with a better rate if one becomes available.
I can prevent the window from closing and the prevent the browser from navigating away. When this happens, a div is displayed with a little for for the user to submit and an option to go ahead and close the window. This all works fine. The problem is that if the user refreshes the page or hits the back or forward buttons then the action is being blocked just as if the user was closing the browser. But I don't care if they go forward or back or refresh the page because that means they are still in the reservation process. Unfortunately, I cannot distinguish between the two types of events.
I am attaching a function to the onbeforeunload event to trigger the message to the user. The site I am working on is an ASP.NET site, if that is helpful to anyone.
Here is the code I am using. The elements divSecondClose and divThankYou are both set to display:none when the page first loads. <%=DisplayThankYou%> is set to 'true' after the form has been submitted so that a thank you message appears.
var showSecondCloseOnExit = true;
var displayThankyou = '<%=DisplayThankYou %>';
if (displayThankyou == true)
{
var divSecondClose = document.getElementById('divSecondClose');
divSecondClose.style.display = '';
var divThankYou = document.getElementById('divThankYou');
divThankYou.style.display = '';
showSecondCloseOnExit = false;
}
else
{
addListener(window, 'beforeunload', CloseWindowEvent, false);
var allLinks = document.getElementsByTagName('a');
for (var linkIndex = 0; linkIndex < allLinks.length; linkIndex++)
{
addListener(allLinks[linkIndex], 'click', function(){showSecondCloseOnExit = false;}, false);
}
}
function CloseWindowEvent(e) {
if(!e) e = window.event;
if (showSecondCloseOnExit)
{
var divSecondClose = document.getElementById('divSecondClose');
divSecondClose.style.display = '';
showSecondCloseOnExit = false;
//e.cancelBubble is supported by IE - this will kill the bubbling process.
e.cancelBubble = true;
e.returnValue = 'RATE CHANGE NOTIFICATION\nWould you take a moment before you leave to help us serve you better?';
//e.stopPropagation works in Firefox.
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
}
}
Have you attempted to sniff the various different values of the event:
*type
*target element
*mouse position
Here is a link with instructive information on accessing each of these. You may be able to figure out what you want through a combination of the above, although the checking all the cases across many browsers seems quite brutal.
http://www.quirksmode.org/js/events_properties.html#type
Also, see these articles for attaching to an event when the window closes and that is all:
How to create popup window when browser close
However, you may also advise the product owner of what you are doing that the cost on doing the functionality you are describing is getting rather high.
NOTE: See Slak's comment here: How to capture the browser window close event? . It may be what you're after.
I have a window I'm opening with a Javascript function:
function newwindow()
{
window.open('link.html','','width=,height=,resizable=no');
}
I need it that once the new window opens that the focus returns to the original window.
How can I do that?
And where do I put the code - in the new window, or the old one?
Thanks!
This is known as a 'pop-under' (and is generally frowned upon... but I digress).. It should give you plenty to google about
You probably want to do something like:
var popup = window.open(...);
popup.blur();
window.focus();
Which should set the focus back to the original window (untested - pinched from google). Some browsers might block this technique.
After calling window.open, you may try to use
window.resizeTo(0,0);
window.moveTo(0,window.screen.availHeight+10);
this way can not really open window in background, but works in similar way. Chrome works fine, did not try other browser.
If Albert's solution doesn't work for you and you actually want the window visible, but to be opened behind the current window, you can try opening a new tab in the opener window and closing it right away, this will bring the focus back to the opener window.
window.open('link.html','','width=,height=,resizable=no');
window.open().close();
However, I believe whether the second window opens in a tab or a new window depends on your browser settings.
Please don't use "pop-unders" for evil.
You can use either
"blur" or
"focus" to do that required action.
"blur"
function newwindow()
{
var myChild= window.open('link.html','','width=,height=,resizable=no');
myChild.blur();
}
"focus"
function newwindow()
{
window.open('link.html','','width=,height=,resizable=no');
window.focus();
}
Put the code in your parentWindow (i.e. the window in which you are now)
Both will work.
tl;dr - in 2022 - ctrl/cmd clicking on a button and window.open(url, "_blank") in a javascript button handler's for loop will open multiple tabs in the background in Chrome.
I'm looking for this as of 2022 and none of the answers here worked (here and everywhere else I looked). My use case is clicking a button in a (progressive) web app which opens deep links to items in a list in background tabs (i.e. not "for evil").
It never occurred to me that ctrl/cmd + clicking on the button would open tabs in the background, but it does just as if the user clicked on an anchor tag itself directly - but only in Chrome. Combined with Chrome's relatively recent tab grouping feature, this can be very useful inside PWAs.
const isMozilla =
window?.navigator?.userAgent?.toString().toLowerCase().includes('firefox') ?? false;
for (let index = 0; index < urls.length; index++) {
const url = isMozilla ? urls.reverse()[index] : urls[index];
window.open(url, "_blank");
}
Note: I reverse() the array on Mozilla to get the order of newly created tabs as the user would expect them.
You can just use '_self'. It will be stay to the same page an
window.open(url, '_self');
i have Problem with opening popups in javascript i have this function to open my popups in IE6 and IE7:
function open_window(Location,w,h) //opens new window
{
var win = "width="+w+",height="+h+",menubar=no,location=no,resizable,scrollbars,top=500,left=500";
alert(win) ;
window.open(Location,'newWin',win).focus();
}
it's working . i mean my new window opens but an error occurs. The Error Message is :
'window.open(...)' is null is not an object.
do you want to countinue running script on this page ?
then i have button in onclick event it's will call a function to close current window an refresh the opener function is
function refreshParent(location)
{
window.opener.location.href = location ;
window.close();
}
it's also gives me error : window.opener.location is null or not an object but i'm sure i'm passing correct parameters
i call it like this :
for second part :
<input type="button" name="pay" value="test" onclick="refreshParent('index.php?module=payment&task=default')" >
for first part :
<a onclick="javascript:open_window('?module=cart&task=add&id=<?=$res[xproductid]?>&popup=on','500' , '500')" style="cursor:pointer" id="addtocard"> <img src="../images/new_theme/buy_book.gif" width="123" border="0"/> </a>
it's really confuse me . Please Help ;)
When popup windows opened using window.open are blocked by a popup blocker, a feature of pretty much any modern browser these days, the return value of window.open() is not a window object, but null.
In order to circumvent these issues you would need to test the value returned by window.open() before attempting to invoke any methods on it.
Below is a piece of code to demonstrate how to go around this problem:
function open_window(Location,w,h) //opens new window
{
var options = "width=" + w + ",height=" + h;
options += ",menubar=no,location=no,resizable,scrollbars,top=500,left=500";
var newwin = window.open(Location,'newWin',options);
if (newwin == null)
{
// The popup got blocked, notify the user
return false;
}
newwin.focus();
}
In general, popup windows should be used only as a last resort or in controlled environments (internal company website, etc). Popup blockers tend to behave in very inconsistent ways and there may be more than a single popup blocker installed in a given browser so instructing the user on how to allow popups for a given website is not necessarily a solution. Example: IE7 + Google toolbar = two popup blockers.
If I may suggest, perhaps you should consider using something like this:
http://jqueryui.com/demos/dialog/
The advantages are numerous:
Skinnable, so you can create a more consistent look to match your website.
No popup blockers.
Good API and documentation that is consistent across most, if not all, major browsers.
If you still require that the newly opened "window" contain an external URL, you could use an IFRAME inside the opened dialog window.
Hope this helps,
Lior.
Works perfectly fine for me. Tested in IE6/7/8.
Of course I couldn't test it with your URLs so I replaced these with simple filenames. I'd suggest you try it also with simple filenames and see if it also fails then.
Beside that...
You don't need to add "javascript:" at the beginning of onclick attribute value.
It would also be good if you added a href="..." attribute to the link with the same URL that you give to open_window. Then it would become a real link and you wouldn't have to add cursor:pointer to it. For example:
<a href="?module=cart&task=add&id=<?=$res[xproductid]?>&popup=on"
onclick="open_window(this.href, '500' , '500'); return false;"> ...
Here is a way to have your cake and eat it too
I have not tested it on all browsers but it should really work
function open_window(url,target,w,h) { //opens new window
var parms = "width="+w+",height="+h+",menubar=no,location=no,resizable,scrollbars,top=500,left=500";
var win = window.open(url,target,parms);
if (win) {
win.focus();
return false; // cancel the onClick
}
return true; // make the link perform as normal
}
Using the link
<a href="?module=cart&task=add&id=<?=$res[xproductid]?>&popup=on"
target="newWin"
onclick="return open_window(this.href,this.target,500,500)"
id="addtocard"><img src="../images/new_theme/buy_book.gif" width="123" border="0"/></a>
which even saves you the silly cursor thing since it is an actual link which works even when JS is turned off