I am in the midst of working on a project that is session-based. I was thinking that similar to a bank, I'd create a check and offer users the ability to thwart a session time-out.
I was thinking about creating a setInterval that would check a blank page that requires auth. If the timer is getting close to end-times, it'd throw up a dialogue advising the user that session is near end. A 'stay logged in' button would reset the timer, and they'd also be presented with an option to log off. If the set interval gets a '401' from the checker page, the current page would be refreshed to the login screen.
Does this make sense? Would the setInterval bog down the browser?
As an aside: what is the easiest way to clearInterval based on user interaction? Would I need to check for every keypress, and/or mouse event? Or is there a broader way of checking if the user is interacting with the page (like a focus check or something)?
Tanka.
So, I had some problems with the framework I'm using.. The session handling is not very good, therefore there seemed to be a problem with updating the session timout instead of having it timeout always based on the time since login, as opposed to since last activity. Anyway, got that handled. The issue I'm wondering about now is that by checking to see if the session is still authenticated via setInterval, the session will be updated via the check, therefore the session will never timeout. Or, am I missing something?
I decided to handle it just with javascript. Set the timeout to never in the framework config, and am handling timeouts with setTimeout exclusively.
function alerter(msg){
//warn user session about to expire; give opportunity to save
}
function killSess(){
window.location = '/logout';
}
function sessTimer(time){
timerID = window.setTimeout('killSess();',time);
}
function observe(div){
Event.observe(div, 'click', function(){
clearTimeout(timerID);
sessTimer(30000);
});
Event.observe('bodyDiv', 'keydown', function(e){
clearTimeout(timerID);
sessTimer(30000);
});
}
Does this make sense? Would the
setInterval bog down the browser?
This should work fine. So long as the interval is fairly large (a few seconds to a minute) and does not increase the size of a global data structure with each iteration, I don't anticipate it bogging down the browser.
As an aside: what is the easiest way
to clearInterval based on user
interaction? Would I need to check for
every keypress, and/or mouse event? Or
is there a broader way of checking if
the user is interacting with the page
(like a focus check or something)?
Maybe adding a few event handlers to a top-level page element such as a container div might be helpful.
It makes perfect sense, and setInterval wouldn't bog down the browser, as long as you make sure not to register it once more when it's already registered.
You only want to run clearInterval on the click of one specific button ("no, don't poll the browser", or "log out"), so i don't quite see the problem in your last paragraph...?
Other than that, I'll just add that upon 401, you shouldn't refresh to login screen. Just notify the user that the session seems to have been lost, so that the user can decide on his own to save anything he might be working with, or perhaps to log in again in a new tab.
Related
I am making a browser game in html, css, and javascript, written in perl. Health and stamina are kept in the server and I use javascript to show the user a live updated count of these stats while the current page is loaded. This works fine, however if the user switches tabs or switches away from the browser and leaves it running in the background, the count value you see when you return does not keep up properly. So when you switch back to the browser, your counter might say 50/100 stamina when you actually have 100/100. So when you do something in the game (loads a new page) the server updates the counter to the true amount because the javascript is just keeping time to show the user a "live" rolling view in the browser.
Is there a way to ensure the javascript counter will continue to function even if the page/tab isn't active or on the forefront? Aside from completely re-writing my game to include continuous live server pushes in what is displayed on the browser to the user?
Say you are playing the game. You see your health and stamina regenerating. You switch to another program for a minute, then return to the game in the browser. You notice your health and stamina have not updated while you were away. But when you perform an action in the game, this value is updated to what it should be because it is tracked internally on the server. This is what I would like to fix. Hope that makes sense!
I have not tried anything to fix this issue yet besides searching the web and ending up on this site without a really "good" answer in sight, so I decided to ask the question.
Continuous server pushes wouldn't work either. Anything in the main event loop like a timer, or events happening when it's out of focus, gets slowed down by the browser to conserve resources. Some mobile browsers will stop it together.
The answer to the question is to change how your app keeps track of these stats.
Now some will say to use WebWorkers to run the timer in a separate thread but this won't solve all your issues. You'd still have a different version of the issue, like if someone restored your webpage from sleep or something along those lines. No background task can survive that.
You mention that you track these stats also on the server. That's convenient, so the most obvious thing you should do is detect when the tab comes back into focus using the Window focus event. You would then make all the calls to the server to fetch the most up-to-date stats and reset the timers based on that fresh data. To stop it from showing stale data while the request is in flight, you might choose to show a loading spinner or something during that period.
Another common way of fixing this is you keep around on each timer increment a var which says when the data last came back (a timestamp). When you leave focus, you detect this with the blur event and store that last timestamp somewhere. Then they come back into focus, you handle the focus event and calculate the difference between the current time and the last recorded time before defocus (blur). You may be able to recalculate from this period what the values should be.
But if your server has this info, it'd be far less error-prone and easy to just ask the server when they refocus.
I am supporting an e-commerce app, which pretty much makes and submits orders.
A user found that if they submit their order, and press back really quickly, they can cause an error condition.
I want to prevent this. When the user clicks submit, I want to bind some kind of event to the browser's back button that instead will redirect them to the Index page. However, after about two hours of Googling (including a few StackOverflow topics), I have not found any clear way of influencing the behavior of the back button.
I briefly attempted to use history.pushState(), but as the HTML 5 documentation mentions, that will not cause a redirect; it merely alters the displayed URL/state.
Similarly, the history.onpopstate event appears unhelpful, because it occurs whenever a state is removed from the history listing; I'm looking for an event that occurs whenever the history listing is traversed backwards.
Question: Does an event for the browser's back button, or at least a way to prevent this particular stupid user trick exist?
You can't listen to the browser back button because it's outside of your reach (it's not part of the DOM).
What you can do is fix the previous page so that it detects if you've used the back button.
Without more information I can't give you any tips on how to achieve that.
Also, an error condition is not necessarily a bad thing. Just make sure it's clear what is happening: the error message should make sense.
Wrong answer...
Instead listen to window.onBeforeUnload and ask the user if he knows what he is doing. Return false if not. This is usually done via a confirm dialogue
I'm looking to implement a warning if the user attempts to leave the order process before it's completed in any fashion other then of course following the payment button.
Something like this:
<script type="text/javascript">
window.onbeforeunload = function(){
return 'You must click "Buy Now" to make payment and finish your order. If you leave now your order will be canceled.';
};
if document.getElementsByClassName('eStore_buy_now_button').onclick = function(){
};
</script>
I'm sure that's detrimentally wrong in a few ways, but it's the best way I can illustrate what I'm trying. And I understand some browsers will display default text instead of the actual warning I've written, that's fine.
A few notes, I'd rather use plain old JS instead of loading up jQuery for just this one simple task. There are no settings on the page so it's a simple leave page or click "Buy Now" operation.
UPDATE:
I assure you it's not for my sake, it's for the user's sake. Although it's explicitly explained (what to do), I think user's are jumping the gun and leaving before the process is truly finished out of an instant gratification, ignore the messages kind of mentality. It's a simple 2-step process, they submit the details for the project and then make payment. For whatever reason they're submitting details and then not following through with payment about 50% of the time. And then they'll follow up "So, are you working on the project or what?" and then I have to explain "You never finished your order." They follow up with a "Whoops, here ya go."
Unfortunately, I would chalk this up as marketing and web design 101. Rule #1, people are dumb. Not to be taken in a rude or pessimistic sense. Basically, the idea is assume everyone is dumb in your design, instruction so that you make something so easy a five-year-old can do it. I totally agree with not holding users hostage. But this page is ONLY reached in the middle of their intended order process that THEY initiate (this page will never be reached in a browsing sort of way). So I think it's a pretty legitimate use case where you're saving a common user mistake from themselves. A demographic of customers that are not tech-savvy, so they honestly need such guidance.
document.querySelector('.eStore_buy_now_button').addEventListener("click", function(){
window.btn_clicked = true; //set btn_clicked to true
});
window.onbeforeunload = function(){
if(!window.btn_clicked){
return 'You must click "Buy Now" to make payment and finish your order. If you leave now your order will be canceled.';
}
};
This will alert the user whenever the page unloads (eg leaving the page) until btn_clicked is set to true.
DEMO: http://jsfiddle.net/DerekL/GSWbB/show/
Don't do it.
There is a fine line in terms of usability - on one hand sometimes I may have intended to place an order but accidentally left the page; on the other hand it could get annoying pretty quickly. When abrowser is set up to save previous session (i.e. reopen tabs on next launch) and one page behaves this way, you'll end up with only that tab re-opened next time (confirmed on Mac Safari), discarding the rest of the tabs. They'll not be buying from you again!
I'd suggest you make it clear to the user by means of inline messages that the order has not been submitted yet and they still need to confirm their action, but if they were to accidentally navigate away you should make it easy to pick up where they left off. Would be fairly trivial to store such info in a cookie so that on subsequent page visits the user would be prompted with "you have an incomplete order for ..., would you like to finish it now?"
As an alternative, you could use rely on an inactivity alert (think of online banking prompting you when your session is about to expire) to bring the user back to the "complete order" page if they get distracted.
If you are certain you want to rely on this event, the answers to this question may provide better insight. Basically, the functionality or its implementation beyond a basic text warning should not be relied onto because of inconsistent (?) implementation across browsers as well as possibility of having it blocked by the user.
Another update:
Prompted by Derek's comment on this approach being used by Gmail etc., I've come across an article suggesting you stick with onunload instead and rely on AJAX calls to save the state of the page - which backs my thoughts on allowing the user to pick up where they left even if the javascript event is never triggered.
basically what i am doing is set a timer to logout the user after a hour has passed but only if the user is inactive so i want to restart the timer after user has did any activity (scroll, keypress, mousemove, click) the thing is that the timer doesn't reset or something else thats why in the logout function i want to know did the timer actually reset and thats why i want to know the time passed by the timer.
i am using javascript, any help pls?
If this is a "feature" -- sure use Javascript, but if security is your aim, use server side, no doubt about it.
It would be a big nuisance to have to code something to track every little change that could happen, scroll, click, focus, keypress, etc, to determine if the user was "idle" or not -- so it's an idea to use something like erichydns idleTimer, jquery plugin: http://www.erichynds.com/jquery/a-new-and-improved-jquery-idle-timeout-plugin/
edit: this would be more suitable for you: http://paulirish.com/2009/jquery-idletimer-plugin/
demo is available here which shows in real time if the user is "idle" or not http://paulirish.com/demo/idle-timer
You can clar the setTimeout using the following code:
var t = setTimeout(myFunction,100000);
clearTimeout(t); //clear the timeout
If you want to know how much time is left, then you have to count the seconds or so ;)
Is there a possible way to synchronize events in javascript?
My situation is following: I have a input form with many fields, each of them has a onchange event registered. there is also a button to open a popup for some other/special things to do in there.
My requirement is, that the onchange event(s) are finished before I can open the popup.
Any ideas how I can achieve that without using setTimeout?
EDIT: further explanation of requirements:
To clarify my situation I try to detail what I'm doing.
I got a form with some input items (order entry matrix form, e.g. article, serial#, count). Every time user changes data in one of the fields an ajax call is triggered by an onchange event to validate the user input and read additional data (e.g. presetting/formating one of the other fields). These ajax calls are heavy and cost time, so I have to avoid duplicate validations.
There is also a button which opens a popup which gives the user an other form to change data he entered before line by line, so it is absolutely necessary that all validations are done before this popup is opened.
At the moment I try to synchronize the onchange events and the popup opening using setTimeout (popup isn't opened before all validations are done), which causes problems at my customers site because these popups are trapped by the popup blocker.
So I need to open my popups without getting stopped by some popup blocker (IE 6/7/8).
Because of my matrix-form I just can't validate all input items before opening the popup, I need to validate only those which have been changed and are not validated yet (should be at most 1).
It sounds like you are doing form validation, with an automatic popup when the form has been fully completed. To do that, you write a single validation function in javascript that checks every field on the form. You can fire this function from each of your OnChange events, and have the function open the popup when the entire form successfully validates.
Consider checking out jQuery, when you have a little free time.
http://jquery.com/
you can set up a little callback to your onchange events to insure that all of your validation occurs before the popup.
function onChange(callback)
{
// Do validation
// Call the callback
callback();
}
function showPopup()
{
// Show the popup
}
Then on your onchange call just call
onChange(showPopup);
If you set a global variable and use setTimeout to check if it is set properly. Depending on how complex the situation is you can either use a boolean, two booleans, a number that increments, or even an object. Personally I would proly use an object as that way I know which one hasn't fired yet. something like var isDone = {username: 0, password: 0, password2: 0};
Let assume by input fields you are meaning only text inputs and not any checkboxes or comboxes( I'm guessing you are trying to make a sort of auto-completion).
My advice is to use onkeyup and onkeydown.
var keypressed = false;
function onkeydown( )
{
keypressed = true;
}
function onkeyup( )
{
keypressed = false;
setTimeout( function()
{
if (!keypressed)
show_popup();
else
setTimeout( this.calee,1000)
}, 1000 );
}
Set flags (variables) for each group of validations.
Initiate the flag at 0.
Set the flag to 1, when
validation is complete for the group.
When the user pops the button, if all
flags are 1, popup the window.
The callback that Jon mentioned would solve the problem of "what do you do if they are not yet all validated?"
EDIT: Added after clarification:
Have you considered adding the popup button, via DOM methods (easy) (or innerHTML, if you like), after everything is validated? That way, there is no option shown before its time. :D
Also, do you test if a popup is blocked? If it is, you could branch to either a notice to the user that their blocker is blocking the editor; or to loading your editor into an iframe automatically; or to loading the editor to the main page via DOM methods (appending documentFragment, etc.).
Some blockers give users the option to block even popups generated from clicking on links (which were traditionally off limits to blockers). I would think you would benefit from some kind of a backup method, or at least a warning system in place regardless.
HTH
i don't think i have completely understood your question, but here are some thoughts on solving problems you may have :)
first, i'd deactivate the popup-opening button when the ajax call is sent. then, when the requested data arrives and all validation is done, activate it again. you can do this with a counter: increment it for every sent request, decrement it as soon data arrives and validation is completed. activate the popup opening button when data arrives and the counter is zero. this prevents the user from clicking the popup opening button while there are still validation requests pending.
you can use the same technique for the input fields themselves: lock the input fields that await validation by setting them to readonly, unlock them when everything is done.
to prevent problems when the user changes form values while the ajax call hasn't yet returned, you have several options:
use a timer for sending the request: everytime an onchange event is fired, wait x seconds before sending the request. if another onchange event happens before the ajax request is sent, reset that timer. this way, several onchange events withing a certain timeframe trigger just 1 ajax request. this helps reducing load.
you can calculate and store checksums for every position, so if an onchange event is fired, calculate the checksums again and compare them. this way you know which parts really have been changed, avoiding unnecessary validation requests.
also, never bet on time (if i understood the settimeout stuff right). x seconds may be enough under normal circumstances, but in the worst case ...
We needed something similar for a wizard where some steps required AJAX validation. The user wouldn't be allowed to close the wizard by clicking Finish if there were any pending validations. For this we simply had a counter for pending validations, and a flag to signal if the user was wishing to close the wizard. The basic algorithm was:
If a new AJAX validation is initiated, increment the "pending" count.
When an AJAX validation returns, decrement the "pending" count.
If, upon decrementing, the pending count reaches zero, check the "finish" flag; if it is set, finish the wizard.
When the user clicks Finish, check the "pending" count; if it's zero, finish the wizard; it it's non-zero, set the "finish" flag.
This way, synchronization can be handled with just two variables ("pending", "finish").
I strongly advise against using multiple flags for each different AJAX operation; a state machine usually gets out of hand when states are tracked with multiple state variables. Try to avoid it unless it's absolutely necessary.
I also don't suggest using setTimeout to arbitrarily wait until desired conditions are met. With the counter approach above, your code will act on changing conditions, as soon as they change.