Does JQuery $.post() not work with document.onbeforeunload event? - javascript

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 :)

Related

How can I detect back button in the browser?

I have a function named back() which will be used for ajax calls. Actually I have an array stack contains last 5 search results and that back function will switch to the previous result set (according to that array stack) and it even changes the URL using window.history.pushState() when you click on the back button.
That back button I was talking about, is an element inside the browser which revokes back() function. Now I want to revoke back() function also when user click on the back button of the browser. Something like this:
window.onhashchange = function() {
back(); // this function also changes the url
}
But sadly window.onhashchange will be revokes twice when I click on the back of the browser. Because window.onhashchange will be revoked when you change the URL using window.history.pushState().
Anyway, how can I detect what things changes the URL? Either my JS code or the back button of the browser?
You can use performance.navigation.type
At any given point, for example on document.onload, you can read the value of type and, if it's:
0 The page was accessed by following a link, a bookmark, a form submission, a script, or typing the URL in the address bar.
1 The page was accessed by clicking the Reload button or via the Location.reload() method.
2 The page was accessed by navigating into the history.
255 any other way.
Just beware that support is limited according to the compatibilty table.
However, from the looks of it, it seems the table is outdated. It says it is not supported on chrome and I just tested it and works as expected on my chrome version (67.0)
One of solution is to implement onunload event with localstorage option.
This is from my head maybe you will need correction but this is base !
var history = [];
window.onload = function(){
var handler;
if ( localStorage.getItem('history') == null ) {
// FIRST TIME
history[0] = window.location.href;
localStorage.setItem("history", JSON.stringify(history));
}
else {
handler = localStorage.getItem('history');
handler = JSON.parse(handler);
history = handler;
// Just compare now
if (history[history.length-1] == window.location.href) {
// no change
} else {
history.push(window.location.href);
}
}
}
window.onunload = function(){
localStorage.setItem('history', JSON.stringify(history));
}
Note :
Since 25 May 2011, the HTML5 specification states that calls to
window.alert(), window.confirm(), and window.prompt() methods may be
ignored during this event. See the HTML5 specification for more
details.

How to call window.unload

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.

Running some code when browser is closed

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.

PJax - how do I turn off the modified behaviour

I've got PJax up and running on my test site - it works a treat. However it relies heavily on a lot of javascript widgets and hence leaks memory.
Since I don't have time right now to re-write every widget, I thought that a simple solution would be to do a normal page load after, say 20 pjax page transitions. A simple plan....but it doesn't seem to be possible.
$.pjax.disable();
....still fetches the content via AJAX, but doesn't change the page.
$(document).pjax();.
...doesn't change the behaviour
$.pjax.handleClick = function (event, container, options) { return; };
...doesn't change the behaviour
$.pjax.state.timeout = 0;
...doesn't change the behaviour
delete $.pjax;
...breaks navigation
$.pjax.defaults.timeout=0;
...doesn't change the behaviour
How do I suspend pjax?
If you add a listener for pjax:beforeSend, you can capture the requested URL, set location.href yourself and return false to cancel the pjax behavior. That is how I'm doing it with the following code:
var pageLoadCounter = 0;
var MAX_PAGE_LOADS = 20;
$(".pjaxContainer").on("pjax:beforeSend", function (e, xhr, settings) {
if (++pageLoadCounter > MAX_PAGE_LOADS) {
// URI can be found at https://github.com/medialize/URI.js
var uri = URI(settings.url);
// Remove _pjax from query string before reloading
uri.removeSearch("_pjax");
location.href = uri.toString();
return false;
}
});
I've discovered that changing the id of the pjax container div gives me the desired result - although this seems like a bit of a kludge. It would also be possible by changing the timeout of the ajax request to 0 - but I still need to work out how to do this.
I did ask on the PJax github page about this but so far have not received a response.

How can I detect with JavaScript/jQuery if the user is currently active on the page?

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.

Categories