jQuery idleTimer plugin
There are a few cases where you want to know if the user is idle. Namely:
- You want to preload more assets
- You want to grab their attention to pull them back
- You want close their banking session after 5 minutes of inactivity. (Jerk!)
- You want the site to sneak off the screen and see if they notice ;-)
Nick Zakas wrote a script for YUI3 to handle these cases. His writeup has a great description of the architecture approach he took to the script.
In my jQuery adaptation, I did a few different things:
- Leveraged event namespaces for easy unbinding
- Considered mousewheel as activity, in addition to keyboard and mouse movement.
- Gave it a bit more jQuery-ish of an API
To use:
// idleTimer() takes an optional argument that defines the idle timeout // timeout is in milliseconds; defaults to 30000 $.idleTimer(10000); $(document).bind("idle.idleTimer", function(){ // function you want to fire when the user goes idle }); $(document).bind("active.idleTimer", function(){ // function you want to fire when the user becomes active again }); // pass the string 'destroy' to stop the timer $.idleTimer('destroy');
Get the source on github (4.6k unminified)
View the demo
Note: If you want to change the timeout interval, you'll have to destroy the existing timer first.
// you can query if the user is idle or not with data() $.data(document,'idleTimer'); // 'idle' or 'active' // you can get time elapsed since user when idle/active $.idleTimer('getElapsedTime'); // time since state change in ms
You can get the latest code, naturally, on github.
Why would you want this? Lets say you want ..
- One Timer to restore the forms, messages boxes, etc.
- Another Timer of a different length timeout to notify about expiration sessions.
// bind to specific elements, allows for multiple timer instances $(elem).idleTimer(30*1000); $(elem).idleTimer('destroy'); $(elem).idleTimer('getElapsedTime'); // some ms something $.data(elem,'idleTimer'); // 'idle' or 'active'
Notice this new API is on $.fn.idleTimer, as in it works on a jQuery collection instead of just the jQuery global object.
If you're using this along with the old $.idleTimer api, you should not do $(document).idleTimer(...)
All these element-bound timers will only watch for events inside of them. You may just want to watch page-level activity, in which case you may set up your timers on document, document.documentElement, and document.body. Those will allow three separate timers that will catch all page activity.
Again, check out the demo or view the source on github. :)
Follow me on twitter: @paul_irish
This looks very useful. You should add the destroy trick to infinite scroll.
@Nate, I'm about to do some infinite scroll upgrades, and destroy is certainly a good call. Thx Nate!
Great work Paul. I'm gonna find a reason to use this nice and soon.
A tiny non–issue — it doesn't register me as active on just a mouse click, without moving the mouse.
@Einar, Aye. I suppose a click should be included. (Though it'd be hard to click without mouse movement, eh) But the overhead is pretty minimal. :)
FWIW it currently watches these events:
'mousemove keydown DOMMouseScroll mousewheel'. I'll throw click in, too.Very nice, I can see this being used for a web-based chat script.
Thanks a ton! I have been thinking about something like this for a while now.
Great i found my solution..
Hi I'm using this plugin and it's working very well except for one problem. It seems to be interfering with the jQuery ui dialog feature. When I include $.idleTimer(120000) in my script firebug shows a 'too much recursion' error when I attempt to close an open modal dialog. When I remove that line of code it works fine. Any ideas? Thanks in advance.
@Marc Thanks for the bug report Marc. It looks to be interfering with any unbind() calls that use namespaces. In this case:
$(document).unbind('.dialog-overlay')Turns out that
$(foo).bind('click.bar mousewheel.bar ',fn)causes a recursive loop in $.event.remove(). {There's an extra space}Gave it a quick $.trim() and we're back in business.
Committed to github with version 0.6.080605.
Wow amazingly quick response thanks - Got everything fixed before I could even get back from work! @Paul Irish
Hi,
great plugin, but I think there´s a little bug (tested on the demo site):
If you are idle and simply click the mousebutton (without moving the mouse) the "active.idleTimer" is fired but the idle timer doesn´t work anymore ;)
greetz
ezod
@ezod Good catch. The script didn't restart the timeout after it changed states. (It would be waiting for the next user event.)
Fixed and updated everywhere as ver 0.7.080609.
$.idleTimer('destroy');
Don't forget this!
Looks as though idleTimer doesn't pickup movements over an iframe. When I have idleTimer setup on a parent page and I move my cursor just within the boundary of an iframe on page, the idle.idleTimer still fires its function, then immediately fires active.idleTimer.
Hi
I am trying to use the idle timer for implementing Session time out in my application.
My concern is that if user opens multiple browser windows for the same session(ctrl+N for IE6) and is active on one of the windows the user shouldnt time out
Is there any way I can use this timer to implement this?
I was thinking of having a session cookie and updating the last hit time whenever the user goes active on any window.
Then Check if the time out is reached by comparing the last hit with the current time at periodic intervals of idle time .
My application is a sessionless application .
Pls suggest some possible way.
@pisces Your cookie technique seems reasonable. Probably the best way to handle that I can think of at the moment.
Thank you very much!!!
Very nice and useful.
1 minute and dream become true =)
This is great, but it doesn't work if the user is moving the mouse/using the keyboard in an embedded flash file. I don't suppose there's a workaround for that?
@Aury Newp. Flash and iframes are the two obvious areas where this fails.
Aury seems right is there any way to get this to detect movement in side of a particular frame. Eg the javascript is on the main page then i have 3 frames It would be nice to monitor the one frame but so far no go. Ive tried $(frames["content"].document).bind( and it appears it only works when transitioning or moving over one frame to another not just sitting in the same frame?? any ideas?
@agask2 You'd have to have this script running in each frame, and then tell the top frame the results via window.postMessage() or this sort of thing.
Not terribly trivial.
@Paul Irish
thanks good input! But my problem is I do not know what will be the src for the frame will be. So I cannot put javascript there,It could be google or anything really. I just need the javascript on the outside to montior what is inside the frame for movement. Any ideas there??
This is exactly what I was looking for.
Thanks, Paul :)
@agask2
Frames are tricky and they don't bubble up things like mousemovement to the parent frame. And then due to the Same Origin Policy, you can't inject script into them at will. So you're in a tough place. :)
One technique is to run the pages through a local proxy and inject script into them. That sounds like not fun, though. :/
@Paul Irish
ouch.. yah, I do not foresee that as being an option really. Can you inject script if everything is on the same domain?? maybe? without a proxy? Thanks for all your support thus far. Its a real nice script for a single page.
@agask2 If it's on the same domain you could probably hook into it… i think..
Silly question, but how can I call the static method isIdle?
$.idleTimer.isIdle is undefined
@Frank Watts ,
If you want to just indicate (externallY) that the user is idle, you can trigger the custom event:
I don't want to trigger it, I want to see what the current status is. The reason is because I have another timer running that will autoscroll a page every 15 minutes. I don't want to autoscroll if the user is not idle.
I've updated the script to allow you to query if the user is currently idle or not (through data())
And to get the elapsed time since the last state change. (If you want to say a user has been idle for x seconds….)
It would be great if you could to attach several idleTimer to the document.
cheers
@Maikel
You indicated the use-case for this would be
* One Timer to restore the forms, messages boxes, etc.
* Another Timer to notify about expiration sessions.
It's a good idea. If other people think it would be useful, I'll add it to the script. (Basically it would bind/trigger on individual elements instead of just the document.)
Is there a way to pop up a warning of a pending timeout?
Like this:
You're session is about to end, click here to continue browsing.
For those wondering about implementing expiring sessions/pending timeout, I wrote a blog post on the subject: http://www.erichynds.com/blog/?p=66
If you could implement functionality so we could use several idleTimers that would be great!
I second the call for a version that can do multiple timers. I have a 5 minute and 20 second timeout warning, and this would be great for that.
Great work!
@Paul Irish
$(document).trigger('idle.idleTimer') is not working. It does not execute the function which i have set for idle.idleTimer.
will try immediately, thanx for the functions…
Hey, thanks for this idle timer, it works great. I just can't figure out how to use getElapsedTime. Can it be used to find out how long the user was idle for once they become active again? If so, how?
Very useful. Thanks! One question, how exactly do you use the query feature?
// you can query if the user is idle or not with data()
$.data(document,'idleTimer'); // 'idle' or 'active'
hi paul great script , how to include this script onto php code . i m developing a tracking application in php where in after logging in , suppose he remains out for a minute , it should change to idle state , well how to use your script in my php code .. am newbie in jquery .. Please Help me …
Thanku in adv …
Paul its a very usefule script. But I think this plugin does not work with IE8/Safari. If the mouse/cursor is left on the screen the idle event is raised for a second and goes back to active event. But this works perfectly fine in firefox. Any idea why?
Wouldn't $(window).blur(…) be considered idle time too? Any chance of you adding this? On my site at http://i-emote.appspot.com I use the jQuery Timer plugin to do periodic page updates. When the focus shifts off of the document (window) I stop the timer which effectually halts page updating. I'd like to do the same thing using idle time and if your plugin encapsulated the logic for window.blur and window.focus it would serve all my usecases.
Also, I wasn't able to find this plugin on jQuery's site where they list all available plugins. It would be great to see it listed there as it obviously holds a lot of value for other jQuery users.
Thanks for providing this great plugin to the jQuery community.
Jeff
@Paul Irish a BIG +1 for this feature
I mean a +1 for multiple timers on a page feature
Hey guys! I added support for multiple timers! :)
http://paulirish.com/2009/jquery-idletimer-plugin/#multiple
Thanks Paul this is very useful, the multiple timer is the way to go!
@Paul Irish
Great! I will try it As soon as possible.
Cheers
Your example page has an error. http://paulirish.com/demo/idle-timer
Error: obj is null
Source File: http://github.com/paulirish/jquery-idletimer/raw/master/jquery.idle-timer.js
Line: 106
Browser: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729)
@Chris
Thanks! fixed now.
read more on the bug that caused this.. The Mysterious Firefox setTimeout "Lateness" argument™
Is there a way to detect if the user is idle in any tabs of the browser.
For example, if he is working in another tab, then the event would not be trigger.
Thanks.
There seems to be an inconsistency. User can enter the 'active' state only from the 'idle' state and not from the default 'null' state.
You can check it on your demo - open the page and keep moving the mouse - boxes will never get yellow highlight.
Another inconsistency is that the user is assumed to be 'active for the first x seconds', this is certainly true for the document, but not so for the document elements.
Just to let you know, all of the internal functions (toggleIdState, stop, handleUserEvent) appear to leak into the global scope.
Hi Paul,
Its a nice plugin.Very useful. Thanks.
Using jQuery idleTimer plugin v0.8.092209 have an issue in Google Chrome(v5.0.375.125):
In Chrome, for the below scenarios say:
1)Whenever the user enters an invalid input an alert box pops up and when the user click "Ok" button
2)When the user clicks on the Print pop up "Ok" button
it considers as if the system is in idle state & redirects the user to Login Page.
It works fine in all the above cases with other browsers.
Any idea ? Kindly share your thoughts.
-Thanks