I am trying to detect the window close event that I opened using window.open() in javascript. But for some reason, it doesn't seem to work.
Here is my code:
<html>
<head>
<script>
var clicktest = function() {
var newwindow = window.open("https://www.google.com",'myPopupwindow', "height=640,width=960,toolbar=no,menubar=no,scrollbars=no,location=no,status=no");
newwindow.addEventListener("beforeunload", function (e) {
console.log('hey');
});
}
</script>
</head>
<body>
<button onclick="clicktest()">hey</button>
</body>
</html>
I also tried using
newwindow.onbeforeunload = function () {
console.log('hey');
}
instead of window.addeventlistener(), but both didn't work and I did try using window instead of newwindow, still, it didn't work.
For cross-origin documents, the only solution is to poll the .closed property of the popup Window object.
But that is a very ugly thing to do, so please have a second though about why you need that.
To limit the ugliness, you can power your polling using battery friendly requestAnimationFrame:
const popup = window.open('https://google.com');
waitForClose(popup, e=>console.log('closed'));
function waitForClose(win, cb) {
function poll() {
if(win.closed) {
cb();
}
else {
requestAnimationFrame(poll);
}
}
poll();
}
As a fiddle since StackSnippet's iframes don't allow popups.
Related
Here is my website : http://www.brute.adult. And here is the codepen : https://codepen.io/vaninoo/pen/GMbbEg.
As you can see on the website, when you click on links, many pop-ups appear. I've been trying to make them disappear on unload. Here's how the pop ups are called:
$( "#title1" ).click(function() {
popup1 = window.open("protein.html", "_blank","menubar=no,location=no,resizable=no,scrollbars=no,status=yes,top=0,left=500,width=500,height=500");
setTimeout(function(){
var popup2 = window.open("protein2.html", "_blank", "toolbar=no,scrollbars=yes,resizable=yes,top=300,left=100,width=500,height=600");
}, 500);
setTimeout(function(){
var popup3 = window.open("protein3.html", "_blank","toolbar=no,scrollbars=yes,resizable=yes,top=10,left=2000,width=400,height=700");
}, 1000);
setTimeout(function(){
var popup4 = window.open("protein4.html", "_blank", "toolbar=no,scrollbars=yes,resizable=yes,top=50,left=50,width=400,height=400");
}, 1500);
});
As you can see, some of them are delayed to create a rythm in the windows opening. And their var names are popup1, popup2, popup3, popup4 etc.
Now here are the solutions I've tried, with no success:
1) Closing them one by one, but for a reason I can't figure out, this will work only on popup1:
$(window).on('beforeunload', function() {
if(popup1) {
popup1.close();
}
else {}
});
$(window).on('beforeunload', function() {
if(popup2) {
popup2.close();
}
else {}
});
2) Trying to iterate them. I will get, by adding an alert, the names of popup1, popup2 etc. one by one, so the first part of the "while" works. But the "if" doesn't:
$(window).on('beforeunload', function() {
var popup = "popup";
var i = 0;
while (i < 3) {
namesofpopups = popup + i;
i++;
if(namesofpopups) {
namesofpopups.close();
}
}
});
I've been on this for ages, I made it a lot more easy to understand on the codepen. If someone could help it would be immensely appreciated!
Thank you and sorry for the long post!
It's due to the scope of the popup reference variables. You've defined them all (except popup1) inside the click handler, so they are not accessible from the onbeforeunload event handler.
To fix this it would be better to push the references in to an array which you can loop through when the tab is unloaded, something like this:
var popups = [];
$("#title1").click(function() {
popups.push(window.open("protein.html", "_blank", "menubar=no,location=no,resizable=no,scrollbars=no,status=yes,top=0,left=500,width=500,height=500"));
setTimeout(function() {
popups.push(window.open("protein2.html", "_blank", "toolbar=no,scrollbars=yes,resizable=yes,top=300,left=100,width=500,height=600"));
}, 500);
// other popups...
});
$(window).on('beforeunload', function() {
popups.forEach(function(popup) {
popup.close();
});
});
With this being said, bombarding your users with popups is incredibly annoying. In fact, if you did it to me I'd purposefully not use your website. I'd suggest you look in to using modal popups within your page instead, if you really need the behaviour.
I have tried many methods to detect browser close event through jQuery or JavaScript. But, unfortunately, I have not been able to detect the close. The onbeforeunload and onunload methods are also not working.
How do I detect the window close, unload, or beforeunload events?
Have you tried this code?
window.onbeforeunload = function (event) {
var message = 'Important: Please click on \'Save\' button to leave this page.';
if (typeof event == 'undefined') {
event = window.event;
}
if (event) {
event.returnValue = message;
}
return message;
};
$(function () {
$("a").not('#lnkLogOut').click(function () {
window.onbeforeunload = null;
});
$(".btn").click(function () {
window.onbeforeunload = null;
});
});
The second function is optional to avoid prompting while clicking on #lnkLogOut and .btn elements.
One more thing, The custom Prompt will not work in Firefox (even in latest version also). For more details about it, please go to this thread.
Referring to various articles and doing some trial and error testing, finally I developed this idea which works perfectly for me.
The idea was to detect the unload event that is triggered by closing the browser. In that case, the mouse will be out of the window, pointing out at the close button ('X').
$(window).on('mouseover', (function () {
window.onbeforeunload = null;
}));
$(window).on('mouseout', (function () {
window.onbeforeunload = ConfirmLeave;
}));
function ConfirmLeave() {
return "";
}
var prevKey="";
$(document).keydown(function (e) {
if (e.key=="F5") {
window.onbeforeunload = ConfirmLeave;
}
else if (e.key.toUpperCase() == "W" && prevKey == "CONTROL") {
window.onbeforeunload = ConfirmLeave;
}
else if (e.key.toUpperCase() == "R" && prevKey == "CONTROL") {
window.onbeforeunload = ConfirmLeave;
}
else if (e.key.toUpperCase() == "F4" && (prevKey == "ALT" || prevKey == "CONTROL")) {
window.onbeforeunload = ConfirmLeave;
}
prevKey = e.key.toUpperCase();
});
The ConfirmLeave function will give the pop up default message, in case there is any need to customize the message, then return the text to be displayed instead of an empty string in function ConfirmLeave().
Try following code works for me under Linux chrome environment. Before running make sure jquery is attached to the document.
$(document).ready(function()
{
$(window).bind("beforeunload", function() {
return confirm("Do you really want to close?");
});
});
For simple follow following steps:
open http://jsfiddle.net/
enter something into html, css or javascript box
try to close tab in chrome
It should show following picture:
Hi i got a tricky solution, which works only on new browsers:
just open a websocket to your server, when the user closes the window, the onclose event will be fired
Following script will give message on Chrome and IE:
<script>
window.onbeforeunload = function (e) {
// Your logic to prepare for 'Stay on this Page' goes here
return "Please click 'Stay on this Page' and we will give you candy";
};
</script>
Chrome
IE
on Firefox you will get generic message
Mechanism is synchronous so no server calls to delay will work, you still can prepare a mechanism like modal window that is shown if user decides to stay on page, but no way to prevent him from leaving.
Response to question in comment
F5 will fire event again, so will Atl+F4.
As Phoenix said, use jQuery .bind method, but for more browser compatibility you should return a String,
$(document).ready(function()
{
$(window).bind("beforeunload", function() {
return "Do you really want to close?";
});
});
more details can be found at : developer.mozilla.org
jQuery .bind() has been deprecated. Use .on() instead
$(window).on("beforeunload", function() {
runBeforeClose();
});
Maybe it's better to use the path detecting mouse.
In BrowserClosureNotice you have a demo example and pure javascript library to do it.
It isn't perfect, but avoid problems of document or mouse events...
<script type="text/javascript">
window.addEventListener("beforeunload", function (e) {
var confirmationMessage = "Are you sure you want to leave this page without placing the order ?";
(e || window.event).returnValue = confirmationMessage;
return confirmationMessage;
});
</script>
Please try this code, this is working fine for me. This custom message is coming into Chrome browser but in Mozilla this message is not showing.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript" language="javascript">
var validNavigation = false;
function endSession() {
// Browser or broswer tab is closed
// Do sth here ...
alert("bye");
}
function wireUpEvents() {
/*
* For a list of events that triggers onbeforeunload on IE
* check http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
*/
window.onbeforeunload = function() {
if (!validNavigation) {
var ref="load";
$.ajax({
type: 'get',
async: false,
url: 'logout.php',
data:
{
ref:ref
},
success:function(data)
{
console.log(data);
}
});
endSession();
}
}
// Attach the event keypress to exclude the F5 refresh
$(document).bind('keypress', function(e) {
if (e.keyCode == 116){
validNavigation = true;
}
});
// Attach the event click for all links in the page
$("a").bind("click", function() {
validNavigation = true;
});
// Attach the event submit for all forms in the page
$("form").bind("submit", function() {
validNavigation = true;
});
// Attach the event click for all inputs in the page
$("input[type=submit]").bind("click", function() {
validNavigation = true;
});
}
// Wire up the events as soon as the DOM tree is ready
$(document).ready(function() {
wireUpEvents();
});
</script>
This is used for when logged in user close the browser or browser tab it will automatically logout the user account...
You can try something like this.
<html>
<head>
<title>test</title>
<script>
function openChecking(){
// alert("open");
var width = Number(screen.width-(screen.width*0.25));
var height = Number(screen.height-(screen.height*0.25));
var leftscr = Number((screen.width/2)-(width/2)); // center the window
var topscr = Number((screen.height/2)-(height/2));
var url = "";
var title = 'popup';
var properties = 'width='+width+', height='+height+', top='+topscr+', left='+leftscr;
var popup = window.open(url, title, properties);
var crono = window.setInterval(function() {
if (popup.closed !== false) { // !== opera compatibility reasons
window.clearInterval(crono);
checkClosed();
}
}, 250); //we check if the window is closed every 1/4 second
}
function checkClosed(){
alert("closed!!");
// do something
}
</script>
</head>
<body>
<button onclick="openChecking()">Click Me</button>
</body>
</html>
When the user closes the window, the callback will be fired.
The goal
Send true or false when window is closed.
The problem
When I click on a button, a window is opened with window.open(); syntax. What I need seems to be simple: when the window is closed, return to the window that opened the popup a response from the server, that can be true or false — like the Facebook's API does.
Someone knows how can I do this in a simple way?
Spotlight
I don't want to use jQuery because the page's CSS is overwriting the popup's CSS.
Current syntax
HTML:
[...]
<a href="#" class="share" data-networkName="<?php echo $network->name; ?>">
Share</a>
[...]
JS:
$(".share").on("click", function(event) {
event.preventDefault();
var networkName = $(this).data("networkName");
window.open("share.php?network=" + networkName");
});
This is what I came up with:
UPDATE
receive.html
Share
<script>
var new_window = null;
function openWindow() {
new_window = window.open('return.html');
}
// Callback Function that we will call in child window
function sendMessage(message) {
alert(message);
new_window.close();
}
</script>
return.html
Mark As Shared
<script>
function messageParent() {
// Calls sendMessage function on the parent window.
window.opener.sendMessage("Hello World!");
}
</script>
You could then handle the return value that you would like to in the sendMessage function in the parent window.
This is the simplest method I could come up with. Please let me know if this works.
Try this:
$(".share").on("click", function(event) {
event.preventDefault();
var networkName = $(this).data("networkName");
window.onbeforeunload = function() {
window.open("share.php?network=" + networkName");
}
});
UPDATE
main.php's script:
$(".share").on("click", function(event) {
event.preventDefault();
var networkName = $(this).data("networkName");
window.onbeforeunload = function() {
window.open("share.php?network=" + networkName");
}
function send(msg) {
//send msg to db or store as cookies
}
});
popup.html's script: [Let's say you have a share button called '#popup-btn']
$('#popup-btn').click(function() {
window.opener.send('MSG SENT FROM POPUP {THEY SHARED SOMETHING}');
});
The problem is that the new content will not print (a few more elements).
When the user clicks my print link then I add more html to the document before window.print() is called.
I use ajax to fetch more chapters for a book before printing.
Code:
Print initialized:
var afterPrint = function () {
var timer = setInterval(function () {
afterContentPrint(); // Cleanup html (restore to initial state)
clearInterval(timer);
}, 900);
}
//window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
Event print click:
$("#print-test").click(function (e) {
e.preventDefault();
beforeContentPrint(); // ajax call for additional content, finishing by calling window.print()
});
In function beforeContentPrint():
var jqxhr = $.ajax({
type: "GET",
url: bookURL,
success: function(data) {
.....
.....
$(article).each(function () {
parent.append(article);
});
},
complete: function() {
var timer = setInterval(function () {
window.print();
}, 900);
}
}
The new content is visibly added to the HTML document, so it should work. But only the initial content (before ajax call) is picked up for print.
This solution is for IE and Firefox (onbeforeprint and onafterprint).
Using window.matchMedia('print') seems to work fine in Chrome with this logic.
I don't know why this is happening but there is a working around in mozilla docs; printing a hidden iframe, then you open more chapters of the book with no need to shows up.
Here the link https://developer.mozilla.org/en-US/docs/Printing
Here the code:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>MDN Example</title>
<script type="text/javascript">
function closePrint () {
document.body.removeChild(this.__container__);
}
function setPrint () {
this.contentWindow.__container__ = this;
this.contentWindow.onbeforeunload = closePrint;
this.contentWindow.onafterprint = closePrint;
this.contentWindow.print();
}
function printPage (sURL) {
var oHiddFrame = document.createElement("iframe");
oHiddFrame.onload = setPrint;
oHiddFrame.style.visibility = "hidden";
oHiddFrame.style.position = "fixed";
oHiddFrame.style.right = "0";
oHiddFrame.style.bottom = "0";
oHiddFrame.src = sURL;
document.body.appendChild(oHiddFrame);
}
</script>
</head>
<body>
<p><span onclick="printPage('externalPage.html');" style="cursor:pointer;text-decoration:underline;color:#0000ff;">Print external page!</span></p>
</body>
</html>
1st Attempt : try putting asyn:false in the ajax request of beforeContentPrint, so that the elements will be added first then the print will be called.
var jqxhr = $.ajax({
type: "GET",
url: bookURL,
async:false,
success: function(data) {
.....
.....
$(article).each(function () {
parent.append(article);
});
},
complete: function() {
var timer = setInterval(function () {
window.print();
}, 900);
}
}
2ndAttempt: Take a look Here how to force execution of one function after another.
Hope this helps.
As the elements added aren't shown it can be a little hard to pinpoint the exact problem, but adding elements via appending/inserting into document doesn't always work that well for all browsers and in worst case you will need to add those elements manually by code (document.createElement(), appendChild() etc.).
In an attempt to create a work-around you can try to use MutationObservers to track changes for your article element which can hopefully help you trigger print when DOM is updated properly. The support is fairly good in new browsers (you may have to use prefix in some, f.ex. WebKitMutationObserver) and for older browsers you can provide a fallback - which of course then only get you so far.
This will monitor a target element for changes and fire a callback.
Generic example based on this article:
var article = document.querySelector('#articleID'),
doPrint = false, // must be available in global/parent scope
o,
useFallback = (typeof MutationObserver !== 'undefined');
if (!useFallback) {
o = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
// you can do additional filtering here
// using the mutation object (.name, .type, ...)
if (doPrint) {
doPrint = false;
window.print();
}
});
});
var cfg = { attributes: true, childList: true, characterData: true };
o.observe(article, cfg);
}
Now that the observer is running you can do this modification in your success callback:
var timer; // keep track of setTimeout so we can cancel it
success: function(data) {
...
...
$(article).each(function () {
parent.append(article);
});
// after last element is added, add a "dummy" element
doPrint = true;
if (useFallback) {
// fallback to setTimeout or other solution
}
else {
parent.append('<br />');
}
}
I made an online demo here which sets up the observer and adds some elements. Open console to see actions. The demo is probably too limited data-wise to simulate your situation but can be useful to see the process.
The mechanism used here for triggering print dialog itself can be discussed if is the best - I just provide one for sake of example.
But you can see the observer is triggered when something is added to article. This way you know the DOM has been updated and it should be available for printing. Only the last element added need to trigger the print, hence the doPrint flag.
If you still have no success you will need to consider adding the elements manually the code way or perhaps predefine some elements that you inject when needed (as said, without knowing the full scenario here it has to be with the guess).
It looks like the setInterval, clearInterval is what is messing you up. Change to a setTimeout and get rid of the clearInterval in your afterprint function. I made a fiddle that works in FF and IE9. Fiddle
complete: function() {
var timer = setTimeout(function () {
window.print();
}, 900);
}
Rewriting the question -
I am trying to make a page on which if user leave the page (either to other link/website or closing window/tab) I want to show the onbeforeunload handeler saying we have a great offer for you? and if user choose to leave the page it should do the normal propogation but if he choose to stay on the page I need him to redirect it to offer page redirection is important, no compromise. For testing lets redirect to google.com
I made a program as follows -
var stayonthis = true;
var a;
function load() {
window.onbeforeunload = function(e) {
if(stayonthis){
a = setTimeout('window.location.href="http://google.com";',100);
stayonthis = false;
return "Do you really want to leave now?";
}
else {
clearTimeout(a);
}
};
window.onunload = function(e) {
clearTimeout(a);
};
}
window.onload = load;
but the problem is that if he click on the link to yahoo.com and choose to leave the page he is not going to yahoo but to google instead :(
Help Me !! Thanks in Advance
here is the fiddle code
here how you can test because onbeforeunload does not work on iframe well
This solution works in all cases, using back browser button, setting new url in address bar or use links.
What i have found is that triggering onbeforeunload handler doesn't show the dialog attached to onbeforeunload handler.
In this case (when triggering is needed), use a confirm box to show the user message. This workaround is tested in chrome/firefox and IE (7 to 10)
http://jsfiddle.net/W3vUB/4/show
http://jsfiddle.net/W3vUB/4/
EDIT: set DEMO on codepen, apparently jsFiddle doesn't like this snippet(?!)
BTW, using bing.com due to google not allowing no more content being displayed inside iframe.
http://codepen.io/anon/pen/dYKKbZ
var a, b = false,
c = "http://bing.com";
function triggerEvent(el, type) {
if ((el[type] || false) && typeof el[type] == 'function') {
el[type](el);
}
}
$(function () {
$('a:not([href^=#])').on('click', function (e) {
e.preventDefault();
if (confirm("Do you really want to leave now?")) c = this.href;
triggerEvent(window, 'onbeforeunload');
});
});
window.onbeforeunload = function (e) {
if (b) return;
a = setTimeout(function () {
b = true;
window.location.href = c;
c = "http://bing.com";
console.log(c);
}, 500);
return "Do you really want to leave now?";
}
window.onunload = function () {
clearTimeout(a);
}
It's better to Check it local.
Check out the comments and try this: LIVE DEMO
var linkClick=false;
document.onclick = function(e)
{
linkClick = true;
var elemntTagName = e.target.tagName;
if(elemntTagName=='A')
{
e.target.getAttribute("href");
if(!confirm('Are your sure you want to leave?'))
{
window.location.href = "http://google.com";
console.log("http://google.com");
}
else
{
window.location.href = e.target.getAttribute("href");
console.log(e.target.getAttribute("href"));
}
return false;
}
}
function OnBeforeUnLoad ()
{
return "Are you sure?";
linkClick=false;
window.location.href = "http://google.com";
console.log("http://google.com");
}
And change your html code to this:
<body onbeforeunload="if(linkClick == false) {return OnBeforeUnLoad()}">
try it
</body>
After playing a while with this problem I did the following. It seems to work but it's not very reliable. The biggest issue is that the timed out function needs to bridge a large enough timespan for the browser to make a connection to the url in the link's href attribute.
jsfiddle to demonstrate. I used bing.com instead of google.com because of X-Frame-Options: SAMEORIGIN
var F = function(){}; // empty function
var offerUrl = 'http://bing.com';
var url;
var handler = function(e) {
timeout = setTimeout(function () {
console.log('location.assign');
location.assign(offerUrl);
/*
* This value makes or breaks it.
* You need enough time so the browser can make the connection to
* the clicked links href else it will still redirect to the offer url.
*/
}, 1400);
// important!
window.onbeforeunload = F;
console.info('handler');
return 'Do you wan\'t to leave now?';
};
window.onbeforeunload = handler;
Try the following, (adds a global function that checks the state all the time though).
var redirected=false;
$(window).bind('beforeunload', function(e){
if(redirected)
return;
var orgLoc=window.location.href;
$(window).bind('focus.unloadev',function(e){
if(redirected==true)
return;
$(window).unbind('focus.unloadev');
window.setTimeout(function(){
if(window.location.href!=orgLoc)
return;
console.log('redirect...');
window.location.replace('http://google.com');
},6000);
redirected=true;
});
console.log('before2');
return "okdoky2";
});
$(window).unload(function(e){console.log('unloading...');redirected=true;});
<script>
function endSession() {
// Browser or Broswer tab is closed
// Write code here
alert('Browser or Broswer tab closed');
}
</script>
<body onpagehide="endSession();">
I think you're confused about the progress of events, on before unload the page is still interacting, the return method is like a shortcut for return "confirm()", the return of the confirm however cannot be handled at all, so you can not really investigate the response of the user and decide upon it which way to go, the response is going to be immediately carried out as "yes" leave page, or "no" don't leave page...
Notice that you have already changed the source of the url to Google before you prompt user, this action, cannot be undone... unless maybe, you can setimeout to something like 5 seconds (but then if the user isn't quick enough it won't pick up his answer)
Edit: I've just made it a 5000 time lapse and it always goes to Yahoo! Never picks up the google change at all.