I have a website where each pages need to check if user close the browser, in this case I run some code (releaseLocking).
So on these pages I have implemented this code:
$(window).on('beforeunload', function () {
return "Are you sure you wanna quit ?";
});
$(window).unload(function () {
releaseLocking();
});
It works but I noticed that if I navigate to multiple pages where this code is implemented, when closing the browser, I'll have multiple call to releaseLocking (for each previously visited pages).
I would prefer only run this code for the last page really active. Do you see what I mean?
Do you have any idea how to proceed?
Thanks.
I suggest using localStorage for this. Since localStorage stores variables per domain, it will allow you to check if the code was already executed. Localstorage is also bound to the session, so after the browser is fully closed, your session is gone, causing the localStorage to be cleared so it wont interfere with the next session.
$(window).on('beforeunload', function () {
return "Are you sure you wanna quit ?";
});
$(window).unload(function () {
if ( !localStorage.getItem('lockReleased') ) {
releaseLocking();
localStorage.setItem('lockReleased', true)
}
});
The code above will set localStorage variable lockReleased to true for the first window that closes. The other windows will see the value, and won't call releaseLocking.
In my knowledge it is impossible to detect a browser close separately
from a browser navigation. the browser does not provide the
window with that information.
SEE HERE ALSO
I am not sure this is the only way to do it(neither the best), anyway you should be able to save a sort of session of the user and ask everytime to the server if the page is the last opened.
//the var declaration goes at the beginning of the script
var isLastPage = false;
$(window).on('beforeunload', function () {
//ajax request, the callback will set isLastPage to true if it is the last page opened by the user with that session.
});
$(window).unload(function () {
if(isLastPage) releaseLocking();
});
Server side you should create a session wich stores all the pages of the user(remember to update it via JS when the user closes a page or opens a new one). I think that only via JS is not possible to do it, you need to be helped by the server.
Related
We recently discovered that Chrome no longer supports window.showModalDialog which is problematic because our enterprise application uses this method.
There is, apparently, a short term workaround that allows you to restore showModalDialog but it involves modifying the registry which is too complicated (and risky) four our average user. Therefore I'm not a big fan of this workaround.
The long term solution is obviously to remove all calls to this obsolete method and replace them with a convenient jQuery plugin (such as VistaPrint's Skinny Modal Dialog plugin, for example. Other suggestions are welcome by the way).
The typical scenario we use the modal dialog is to ask the user for Yes/No confirmation before executing an action that cannot be undone, ask the user to agree to terms and condition before proceeding, etc. Typically the onclick event on the "Yes" or "Ok" button in the modal dialog looks like this:
window.returnValue = true;
window.close();
Similarly, the "Cancel" or "No" button looks like this:
window.returnValue = false;
window.close();
The fact that we can return a value from the dialog is very convenient because it allows the "parent" window to be notified whether the user has clicked the "Ok" or the "Cancel" button like so:
var options = "center:1;status:1;menubar:0;toolbar:0;dialogWidth:875px;dialogHeight:650px";
var termsOfServiceAccepted = window.showModalDialog(myUrl, null, options);
if (termsOfServiceAccepted) {
... proceed ...
}
The last thing I'm going to mention about the showModalDialog is that it works great even when the document displayed in the dialog is from a different domain. It's very common for us to have our javascript running from http://the-client.com but the "Terms of Service" web page is from http://the-enterprise-vendor.com
I need a temporary solution that I can deploy ASAP while we work on the long term solution. Here are my criteria:
minimal code change in existing JavaScript
the pop up window must be able to return a value to the "parent". Typically this value is a Boolean but it could be any simple type (e.g.: string, int, etc.)
solution must work even if the URL of the content is from different domain
Here's what I have so far:
1) Add the following method in my JavaScript:
function OpenDialog(url, width, height, callback)
{
var win = window.open(url, "MyDialog", width, height, "menubar=0,toolbar=0");
var timer = setInterval(function ()
{
if (win.closed)
{
clearInterval(timer);
var returnValue = win.returnValue;
callback(returnValue);
}
}, 500);
}
As you can see in this method, I try to make the pop up window look as similar to a dialog as possible by hiding the menu and the toolbar, I setup a time every 500 milliseconds to check if the window has been closed by the user and if so, get the 'returnValue' and invoke a callback.
2) replace all calls to showModalDialog with the following:
OpenDialog(myUrl, 875, 650, function (termsOfServiceAccepted)
{
if (termsOfServiceAccepted)
{
... proceed ....
}
});
The fourth parameter to the method is the callback where I check if the user has clicked the "Ok" button before allowing her to proceed.
I know it's a long question but basically it boils down to:
What do you think of the solution I propose?
In particular, do you think I'll be able to get a returnValue from a window that was opened with window.open?
Any other alternative you can suggest?
I have two ideas that could help you but the first one is tied to CORS, so you won't be able to use it from different domains at least you can access both services and configure them.
FIRST IDEA:
The first one is related to this native api. You could create on the parent window a global function like this:
window.callback = function (result) {
//Code
}
As you can see it receives a result argument which can hold the boolean value you need. The you could open the popup using the same old window.open(url) function. The popup's onlick event handler could look like this:
function() {
//Do whatever you want.
window.opener.callback(true); //or false
}
SECOND IDEA: Solves the problem
The other idea I got is to use this other native api to trigger an event on the parent window when the popup resolves (better known as cross-document messaging). So you could do this from the parent window:
window.onmessage = function (e) {
if (e.data) {
//Code for true
} else {
//Code for false
}
};
By this way you are listening to any posted message on this window, and checking if the data attached to the message is true (the user clicks ok in the popup) or false (the user clicks cancel in the popup).
In the popup you should post a message to the parent window attaching a true or a false value when corresponds:
window.opener.postMessage(true, '*'); //or false
I think that this solution perfectly fits your needs.
EDIT
I have wrote that the second solution was also tied to CORS but digging deeper
I realized that cross-document messaging isn't tied to CORS
I am using web socket connection for communication. But when user refresh page, I want to close this web socket connection.
I also using window.onbeforeunload event to show confirmation box to user with customized text. If user selects 'do not reload' option then no action (which is working fine)
But I want to close web socket connection if user selects reload option. I don't know how to achieve this. I tried to call window.unload and tried to close web socket connection but its not working. My code is as follows.
window.onbeforeunload = function(e) {
return "you are closing this web page';
};
window.unload = function(e) {
webSockect.closeConnection();
};
Please advise how to achieve this.
Window events are prefixed with on.
Try to use window.onunload = ... or even better
window.addEventListener('unload', ...).
When using addEventListener you specify the event name without on prefix.
Read more: WindowEventHandlers.onunload
First of all, there is a syntax error in the code above, you have written:
window.onbeforeunload = function(e) {
return "you are closing this web page';
};
So, type of quotes there should be either single or double, same at start and end of the string.
It is supposed to be, and it will work:
window.onbeforeunload = function(e) {
return "you are closing this web page";
};
====
Back to the point. All you can do with unload prompt is to change the Message. Anything otherwise doesn't work like:
Changing the action on Buttons on the prompt
Changing the Button text of the prompt
Changing the UI of the box
Q. even you write something before the return if the function, that will be ignored by the browser.
You can in fact run a method on close if you assign the method to a variable and then return the variable.
function unloadWebSocket()
{
webSockect.closeConnection();
}
window.onbeforeunload = function(e)
{
var x = unloadWebSocket();
return x;
};
While I have no experience with websockets, I know this works with synchronous ajax requests.
We recently discovered that Chrome no longer supports window.showModalDialog which is problematic because our enterprise application uses this method.
There is, apparently, a short term workaround that allows you to restore showModalDialog but it involves modifying the registry which is too complicated (and risky) four our average user. Therefore I'm not a big fan of this workaround.
The long term solution is obviously to remove all calls to this obsolete method and replace them with a convenient jQuery plugin (such as VistaPrint's Skinny Modal Dialog plugin, for example. Other suggestions are welcome by the way).
The typical scenario we use the modal dialog is to ask the user for Yes/No confirmation before executing an action that cannot be undone, ask the user to agree to terms and condition before proceeding, etc. Typically the onclick event on the "Yes" or "Ok" button in the modal dialog looks like this:
window.returnValue = true;
window.close();
Similarly, the "Cancel" or "No" button looks like this:
window.returnValue = false;
window.close();
The fact that we can return a value from the dialog is very convenient because it allows the "parent" window to be notified whether the user has clicked the "Ok" or the "Cancel" button like so:
var options = "center:1;status:1;menubar:0;toolbar:0;dialogWidth:875px;dialogHeight:650px";
var termsOfServiceAccepted = window.showModalDialog(myUrl, null, options);
if (termsOfServiceAccepted) {
... proceed ...
}
The last thing I'm going to mention about the showModalDialog is that it works great even when the document displayed in the dialog is from a different domain. It's very common for us to have our javascript running from http://the-client.com but the "Terms of Service" web page is from http://the-enterprise-vendor.com
I need a temporary solution that I can deploy ASAP while we work on the long term solution. Here are my criteria:
minimal code change in existing JavaScript
the pop up window must be able to return a value to the "parent". Typically this value is a Boolean but it could be any simple type (e.g.: string, int, etc.)
solution must work even if the URL of the content is from different domain
Here's what I have so far:
1) Add the following method in my JavaScript:
function OpenDialog(url, width, height, callback)
{
var win = window.open(url, "MyDialog", width, height, "menubar=0,toolbar=0");
var timer = setInterval(function ()
{
if (win.closed)
{
clearInterval(timer);
var returnValue = win.returnValue;
callback(returnValue);
}
}, 500);
}
As you can see in this method, I try to make the pop up window look as similar to a dialog as possible by hiding the menu and the toolbar, I setup a time every 500 milliseconds to check if the window has been closed by the user and if so, get the 'returnValue' and invoke a callback.
2) replace all calls to showModalDialog with the following:
OpenDialog(myUrl, 875, 650, function (termsOfServiceAccepted)
{
if (termsOfServiceAccepted)
{
... proceed ....
}
});
The fourth parameter to the method is the callback where I check if the user has clicked the "Ok" button before allowing her to proceed.
I know it's a long question but basically it boils down to:
What do you think of the solution I propose?
In particular, do you think I'll be able to get a returnValue from a window that was opened with window.open?
Any other alternative you can suggest?
I have two ideas that could help you but the first one is tied to CORS, so you won't be able to use it from different domains at least you can access both services and configure them.
FIRST IDEA:
The first one is related to this native api. You could create on the parent window a global function like this:
window.callback = function (result) {
//Code
}
As you can see it receives a result argument which can hold the boolean value you need. The you could open the popup using the same old window.open(url) function. The popup's onlick event handler could look like this:
function() {
//Do whatever you want.
window.opener.callback(true); //or false
}
SECOND IDEA: Solves the problem
The other idea I got is to use this other native api to trigger an event on the parent window when the popup resolves (better known as cross-document messaging). So you could do this from the parent window:
window.onmessage = function (e) {
if (e.data) {
//Code for true
} else {
//Code for false
}
};
By this way you are listening to any posted message on this window, and checking if the data attached to the message is true (the user clicks ok in the popup) or false (the user clicks cancel in the popup).
In the popup you should post a message to the parent window attaching a true or a false value when corresponds:
window.opener.postMessage(true, '*'); //or false
I think that this solution perfectly fits your needs.
EDIT
I have wrote that the second solution was also tied to CORS but digging deeper
I realized that cross-document messaging isn't tied to CORS
I am trying to use $.post to send form data to a server side script to be saved if the user tries to leave the page without submitting the form. I am using the same function attached to a save button and on setInterval set to every 2 minutes, and it works fine. But when I attach the function to document.onbeforeunload it does not work. In firebug, I see the request is being sent, but it looks like it is being stopped before a status code is returned and the page continues to unload. I am still pretty new to Javascript and Jquery and I am not sure if maybe $.post is one of those functions that might not work on the onbeforeunload event. If that is true, is there another way I can send the data if the user tries to leave the page without saving?
This is the function I am calling from the onbeforeunload event:
function ajaxSubmit(){
var blogtitle = $("#title").val();
var publishedstate = 0;
var blogid = $("#blogID").val();
var blogbody = CKEDITOR.instances['body'].getData();
var postdata = {ajaxSubmit:true,title:blogtitle,body:blogbody,published:publishedstate,blog_id:blogid};
$.post('ajaxblog.php',postdata,function(data){
$("#autosaveMessage").html(data);
$("#autosaveMessage").show();
setTimeout(function(){$("#autosaveMessage").hide();},5000);
});
}
and this is how I am calling the function:
var post_clicked = false;
$("#postButton").click(function(){
post_clicked = true;
});
function leaveEditor(){
if(post_clicked==false){
ajaxSubmit();
}
else{
//Do Nothing
}
}
window.onbeforeunload = leaveEditor;
No, and this is by design. It would be remarkably troublesome if a page could use onbeforeunload to indefinitely delay browsing away, persist its presence somehow, etc. One of the most important abilities for a user of a web browser to have is the ability to leave.
Just use the stringy return value—the whole point of it is to remind the user that s/he made changes that will be lost. Like on SO :)
I am needing to detect when a user is inactive (not clicking or typing) on the current page for more than 30 minutes.
I thinking it might be best to use event blubbling attached to the body tag and then just keep resetting a timer for 30 minutes, but I'm not exactly sure how to create this.
I have jQuery available, although I'm not sure how much of this will actually use jQuery.
Edit: I'm more needing to know if they are actively using the site, therefore clicking (changing fields or position within a field or selecting checkboxes/radios) or typing (in an input, textarea, etc). If they are in another tab or using another program, then my assumption is they are not using the site and therefore should be logged out (for security reasons).
Edit #2: So everyone is clear, this is not at all for determining if the user is logged in, authenticated or anything. Right now the server will log the user out if they don't make a page request within 30 minutes. This functionality to prevent the times when someone spends >30 minutes filling in a form and then submitting the form only to find out that they haven't been logged out. Therefore, this will be used in combination with the server site to determine if the user is inactive (not clicking or typing). Basically, the deal is that after 25 minutes of idle, they will be presented with a dialog to enter their password. If they don't within 5 minutes, the system automatically logs them out as well as the server's session is logged out (next time a page is accessed, as with most sites).
The Javascript is only used as a warning to user. If JavaScript is disabled, then they won't get the warning and (along with most of the site not working) they will be logged out next time they request a new page.
This is what I've come up with. It seems to work in most browsers, but I want to be sure it will work everywhere, all the time:
var timeoutTime = 1800000;
var timeoutTimer = setTimeout(ShowTimeOutWarning, timeoutTime);
$(document).ready(function() {
$('body').bind('mousedown keydown', function(event) {
clearTimeout(timeoutTimer);
timeoutTimer = setTimeout(ShowTimeOutWarning, timeoutTime);
});
});
Anyone see any problems?
Ifvisible.js is a crossbrowser lightweight solution that does just that. It can detect when the user switches to another tab and back to the current tab. It can also detect when the user goes idle and becomes active again. It's pretty flexible.
You can watch mouse movement, but that's about the best you're going to get for indication of a user still being there without listening to the click event. But there is no way for javascript to tell if it is the active tab or if the browser is even open. (well, you could get the width and height of the browser and that'd tell you if it was minimized)
I just recently did something like this, albeit using Prototype instead of JQuery, but I imagine the implementation would be roughly the same as long as JQuery supports custom events.
In a nutshell, IdleMonitor is a class that observes mouse and keyboard events (adjust accordingly for your needs). Every 30 seconds it resets the timer and broadcasts an state:idle event, unless it gets a mouse/key event, in which case it broadcasts a state:active event.
var IdleMonitor = Class.create({
debug: false,
idleInterval: 30000, // idle interval, in milliseconds
active: null,
initialize: function() {
document.observe("mousemove", this.sendActiveSignal.bind(this));
document.observe("keypress", this.sendActiveSignal.bind(this));
this.timer = setTimeout(this.sendIdleSignal.bind(this), this.idleInterval);
},
// use this to override the default idleInterval
useInterval: function(ii) {
this.idleInterval = ii;
clearTimeout(this.timer);
this.timer = setTimeout(this.sendIdleSignal.bind(this), ii);
},
sendIdleSignal: function(args) {
// console.log("state:idle");
document.fire('state:idle');
this.active = false;
clearTimeout(this.timer);
},
sendActiveSignal: function() {
if(!this.active){
// console.log("state:active");
document.fire('state:active');
this.active = true;
this.timer = setTimeout(this.sendIdleSignal.bind(this), this.idleInterval);
}
}
});
Then I just created another class that has the following somewhere in it:
Event.observe(document, 'state:idle', your-on-idle-functionality);
Event.observe(document, 'state:active', your-on-active-functionality)
Ifvisible is a nice JS lib to check user inactivity.
ifvisible.setIdleDuration(120); // Page will become idle after 120 seconds
ifvisible.on("idle", function(){
// do something
});
Using jQuery, you can easily watch mouse movement, and use it to set a variable indicating activity to true, then using vanilla javascript, you can check this variable every 30 minutes (or any other interval) to see if its true. If it's false, run your function or whatever.
Look up setTimeout and setInterval for doing the timing. You'll also probably have to run a function every minute or so to reset the variable to false.
Here my shot:
var lastActivityDateTime = null;
function checkActivity( )
{
var currentTime = new Date();
var diff = (lastActivityDateTime.getTime( ) - currentTime.getTime( ));
if ( diff >= 30*60*1000)
{
//user wasn't active;
...
}
setTimeout( 30*60*1000-diff, checkActivity);
}
setTimeout( 30*60*1000, checkActivity); // for first time we setup for 30 min.
// for each event define handler and inside update global timer
$( "body").live( "event_you_want_to_track", handler);
function handler()
{
lastActivityDateTime = new Date();
// rest of your code if needed.
}
If it's a security issue, doing this clientside with javascript is absolutely the wrong end of the pipe to be performing this check. The user could easily have javascript disabled: what does your application do then? What if the user closes their browser before the timeout. do they ever get logged out?
Most serverside frameworks have some kind of session timeout setting for logins. Just use that and save yourself the engineering work.
You can't rely on the assumption that people cannot log in without javascript, therefore the user has javascript. Such an assumption is no deterrent to any determined, or even modestly educated attacker.
Using javascript for this is like a security guard handing customers the key to the bank vault. The only way it works is on faith.
Please believe me when I say that using javascript in this way (and requiring javascript for logins!!) is an incredibly thick skulled way to engineer any kind of web app.
Without using JS, a simpler (and safer) way would simply be to have a lastActivity timestamp stored with the user's session and checking it on page load. Assuming you are using PHP (you can easily redo this code for another platform):
if(($_SESSION['lastAct'] + 1800) < time()) {
unset($_SESSION);
session_destroy();
header('Location: session_timeout_message.php');
exit;
}
$_SESSION['lastAct'] = time();
and add this in your page (optional, the user will be logged out regardless of if the page is refreshed or not (as he logs out on next page log)).
<meta http-equiv="refresh" content="1801;" />
You can add and remove classes to the document depending on the user active status.
// If the window is focused, a mouse wheel or touchmove event is detected
$(window).on('focus wheel touchmove', function() {
$( 'html' ).addClass('active').removeClass('inactive');
});
// If the window losses focus
$(window).on('blur', function() {
$( 'html' ).addClass('inactive').removeClass('active');
});
After that, you can check every while if the html has the "active" class and send an AJAX request to check the session status and perform the action you need:
setInterval( function() {
if ( $( 'html' ).hasClass('active') ) {
//Send ajax request to check the session
$.ajax({
//your parameters here
});
}
}, 60000 ); /* loops every minute */
If your concern is the lost of information for the user after a login timeout; another option would be to simply store all the posted information upon the opening of a new session (a new session will always be started when the older session has been closed/scrapped by the server) when the request to a page is made before re-routing to the logging page. If the user successfully login, then you can use this saved information to return the user back to where he was. This way, even if the user walk away a few hours, he can always return back to where he was after a successful login; without losing any information.
This require more work by the programmer but it's a great feature totally appreciated by the users. They especially appreciate the fact that they can fully concentrate about what they have to do without stressing out about potentially losing their information every 30 minutes or so.