This script challenge got my focus.
Thanks to you, Sandra, who gave me the opportunity of a fun code time on a boring monday evening.
First, I had in mind (because I've read it somewhere... I don't know when) that the beforeunload
event is handled differently depending on the browser and is, therefore, not a safe option.
For example, Chrome is not allowing an alert
or a prompt
on that event, which is exactly what you tried.
But it still, it allows a function to run.
Based on this old answer, I've tested something for you.
As of 2017, the message returned (as suggested in the 2012 answer) is not displayed in Chrome.
But a return true;
works as expected with a default Chrome message:

Now, You don't want this function binded to the beforeunload
event to execute if the target that triggered the event is an internal link.
And I've added to requirements : "Not on page refresh!"
(keydown
on F5)
Okay.
So here is what I have now, which triggers on close tab/browser and on external link click only.
(Taking account of full and/or relative URL).
I've tested it only on Chrome, which I think is the most severe on this event.
It's working.
And this code is fully "Rubber Duck" compliant.
Cheers!
;)
$(document).ready(function(){
console.log("Page has just loaded.");
// Flag to determine if a link click is local or external.
window.localLinkClicked = false;
// flag for the refresh key [F5]
var refreshKey=false;
// Link click handler.
$("a").on("click", function(e) {
// Get the link URL
var url = $(this).attr("href");
console.log("Link clicked. URL: "+url);
// Check if the link is relative to your domain:
// [SUB_DOMAIN] example: www
// [DOMAIN] example: google
// [TLD] example: com
// This regexp (regular expression) takes in account secured and unsecured domains (http:// and https://)
if ( !/^(http)(s?):\/\//.test(url) || /^(http)(s?):\/\/[SUB-DOMAIN]\.[DOMAIN]\.[TLD]\//.test(url) ) {
window.localLinkClicked = true;
}else{
window.localLinkClicked = false;
}
console.log("Local click ? " + window.localLinkClicked);
if (!window.localLinkClicked) {
var leave = confirm("Do you really want to leave our website to follow this link?");
if(leave){
refreshKey=true;
alert("Okay, see you soon!");
}else{
e.preventDefault();
console.log("User has cancelled his navigation.")
}
}
// Reset the local click flag
setTimeout(function(){
window.localLinkClicked = false;
},10);
});
// Handler to detect the refresh key
$(window).on("keydown",function(e){
//console.log(e.which);
if(e.which==116 ){
console.log("User is REFRESHING the page. Do not trigger the confirm to leave.");
refreshKey=true;
}else{
refreshKey=false;
}
});
// On beforeunload event handler.
$(window).on('beforeunload', function(e) {
if(typeof(e)!="undefined" && e.target.tagName!="undefined" && (!refreshKey && !window.localLinkClicked) ){
return true;
}
});
});