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. :)
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
For some reason in Chrome, i had the idle timer setup and working fine, but when i do an alert(adsffd); after I click 'ok' and the popup goes away, it triggers the idletimer and asks if Im still active.
It does not happen in FF, only Chrome (5.0.375.127) Windows 7 pro.
Any help would be great, I even tried destroying before the alert and then re-initiating it after but it doesnt seem to work after that.
I also have the issue with Chrome in version 6.0.472.55 and version 7.0.520.0
Works fine in IE and FF though.
Sorry guys but i'm not gonna have time to dig into this…
Would love some help if you want to help track down exactly why this is happening..
All the code is right here.
http://github.com/paulirish/jquery-idletimer/
I am trying to use your plugin to poll against a cookie. How would I reset the inactivity timer each time it times out?
nevermind. I was calling destroy and then setting the timeout. This was not working. walked away for a couple minutes. looked at the code again and removed the destroy line. works as desired. thanks for the plugin.
Great plugin.
It seems once you destroyed a timer, it cannot be reactivated?
Given this code, which display a "screen lock" div:
$.idleTimer(2 * 1000);
var unlockKeys = [], unlockKeySequences = ["131,133", "27,13"];
$(document).bind("idle.idleTimer", function() {
$.idleTimer('destroy');
$('#lock').show().text(navigator.userAgent);
$(document).keydown(function(e) {
unlockKeys.push(e.keyCode);
$(" + unlockKeys.toString() + ").appendTo('#lock');
var s = unlockKeys.toString();
if (s.indexOf(unlockKeySequences[0]) >= 0 || s.indexOf(unlockKeySequences[1]) >= 0) {
$(document).unbind('keydown', arguments.callee);
$('#lock').hide();
$.idleTimer(2 * 1000);
}
});
});
The idle event is only fired once.
Great answer for your question……..
http://www.swaptechnologies.in/#how-to-detect-idle-time-in-jquery-javascript.html
@Paul Irish
I don't know about the root cause or how to fix it, it has something to do with alert/confirm mucking with timeouts (see more discussion here) but I've found the workaround to be checking the idle state in the idle event:
@T.J. Barbour
Scratch that, this doesn't fix it, I failed to regression test it, plese ignore!
Sorry!
Hi Paul,
Thanks for this blog, i used given code. it is very help full
this is very good functionality. which help people to make very interactive and intelligent site.
Great blog and post. This post in fact just saved my life in a project i'm working on.
Has somebody solved this with frames on the same domain? I need to make the parent document listen to mouse/keyboard activity within a child frame, and execute the script in the parent document as normal (i.e., when the user is idle in both documents, the timeout script executes in the parent document; user activity in either document tells the script that the user is active).
Will pay for a functioning solution.
Paul suggested the solution was something along these lines…
// no guarantees this would work. i'm just guessing
$($('#iframeid').contents()[0].document).bind("idle.idleTimer", function(){
top.$(top.document).triggger('idle.idleTimer');
});
@T.J. Barbour
Here's my work around. In the toggleIndleSTate function, replace the "// reset timeout counter" section with the following:
// reset timeout counter
var elapsed = (+new Date) – f.olddate;
f.olddate = +new Date;
// handle Chrome always triggering idle after js alert or comfirm popup
if (idle && (elapsed < timeout)) {
idle = false;
return;
}
@Young
Slight adjustment to address the issue that the idletimeout may not start if there is no activity after a page loads:
// reset timeout counter
var elapsed = (+new Date) – f.olddate;
f.olddate = +new Date;
// handle Chrome always triggering idle after js alert or comfirm popup
if (idle && (elapsed < timeout)) {
idle = false;
clearTimeout($.idleTimer.tId);
if (enabled)
$.idleTimer.tId = setTimeout(toggleIdleState, timeout);
return;
}
@Young
Slight adjustment to what I have above to address issue where idletimeout may not start if there is no activity after a page loads:
// reset timeout counter
var elapsed = (+new Date) – f.olddate;
f.olddate = +new Date;
// handle Chrome always triggering idle after js alert or comfirm popup
if (idle && (elapsed < timeout)) {
idle = false;
clearTimeout($.idleTimer.tId);
if (enabled)
$.idleTimer.tId = setTimeout(toggleIdleState, timeout);
return;
}
Hi,
Thank you for the excellent plugin. I want to logout the user if he is idle for 3 mins and if he is active, then the timer should reset and re-start counting..
my code is
$.idleTimer(180000);
$(document).bind("idle.idleTimer", function() {
window.location = "Login.aspx";
});
$(document).bind("active.idleTimer", function() {
clearTimeout($.idleTimer.tId);
});
It seems like working. But Am I correct according to this code? Can you please reply so that i can use this good code in my project.
I integrated the fix in a fork on github at: http://github.com/zawaideh/jquery-idletimer
You can grab it from there until it is pulled upstream.
Many Thanks Zaid.Chrome alert issue got fixed in version 0.9.100511 & works fine.Thank you.
I am facing the same issue on Safari browser. I have updated the code block to my JQuery file and it is working for Google Chrome but facing the issue for Safari. Any JS alert or confirm box close triggers JQuery Idletimer plugin.
@Ketan Bhatt
I am using Safari 5.0.5 Is anybody else who is facing similar issue?
Will this work with Iframes at all?
I have a page with 3 html's. There is a main container, that holds 2 iframes ("Top" and "Bottom").
I want to make it so that after 5 minutes of inactivity, iframe "bottom" will reload back to it's orignial source. (bottom.html)
I can't seem to get it to work.
This seems like it would be relatively simple but I am not too familiar with Iframes and I am wondering if this is why I can't get it to work?
Thanks in advance!
Sorry, I should add, I will pay for a working solution for this.
I know there are others that are having similar issues with Iframes but I haven't seen a solution posted.
Thanks again!
Jamie,
This will work fine with iframes.
In each of your iframe, put the following:
handleUserEvent = function(){
top.$(top.document).trigger('keydown.idleTimer');
}
var events = 'mousemove keydown DOMMouseScroll mousewheel mousedown touchstart touchmove'; // activity is one of these events
$(document).bind($.trim((events+' ').split(' ').join('.idleTimer ')),handleUserEvent);
This will simulate activity on the parent document when something happens in the iframe.
You can then use the parent documents timer to control what happens to your iframe after the inactivity timeout
@jamie
Jamie,
This will work fine with iframes.
In each of your iframe, put the following:
handleUserEvent = function(){
top.$(top.document).trigger('keydown.idleTimer');
}
var events = 'mousemove keydown DOMMouseScroll mousewheel mousedown touchstart touchmove'; // activity is one of these events
$(document).bind($.trim((events+' ').split(' ').join('.idleTimer ')),handleUserEvent);
This will simulate activity on the parent document when something happens in the iframe.
You can then use the parent documents timer to control what happens to your iframe after the inactivity timeout
Paul, well done very useful! Can I use this for free on my website which I charge people to use?
I know it has Dual MIT & GPL License, but to be honest all the licensing terminology is all very confusing to me.
Thanks
@Mick Smith
Yup, you can do whatever you want with it :)
Hi,
i hav created one.html page inside body function i hav created iframe.
and i given src=welcome.html. my prob is when page is idle for 5sec it shold show popup win. but when my mouse, key events not not detecting in iframe page means welcome.html page. it's detecting events oly in the one.html page. so pls give me solution.
@Paul Irish
Hey buddy
i used ur code
$(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('getElapsedTime');
//clearTimeout($.idleTimer.tId);
//$.idleTimer.tId = setTimeout(toggleIdleState, timeout);
});
it stops the dialog from generating but it doesn't restart the idletimer or should i say it doesn't reset the timer.
how to call the
$(document).ready(function()
from another function
@Brent
Hi,
i hav created one.html page inside body function i hav created iframe.
and i given src=welcome.html. my prob is when page is idle for 5sec it shold show popup win. but when my mouse, key events not not detecting in iframe page means welcome.html page. it's detecting events oly in the one.html page. so pls give me solution.
@Nagraj
i hav created one.html page inside body function i hav created iframe.
and i given src=welcome.html. my prob is when page is idle for 5sec it shold show popup win. but when my mouse, key events not not detecting in iframe page means welcome.html page. it's detecting events oly in the one.html page. so pls give me solution.
How would I use this to kick someone back to a page after a certain period of time… How can I do this?
hey paul,
i want to see for how long a user was active..i want that value to inserted into the database..can we modify this program to do that??????
Paul, thanks so much for this plugin. Works great, and it seems pretty light on processing considering the fact that 'active.idleTimer' triggers on mouse movement.
Hi Paul,
Thanks for the plugin. It works! But I encountered a bug in clearInterval and setInterval js functions. I fired a clearInterval function when the browser is in idle state and it works great, but when i fire a setInterval function whenever the browser is active, the setInterval function seems to iterate and produce a multiple setInterval functions everytime i enter an idle and active state. Please help. God bless!
I just tried out jQuery 1.7, and your plugin isn't working. I'm using it as a time out for session login.
John Safar is right. I dug into the plugin, and found two things one can do to get at least a single, document-wide idle/active timer again.
1) Replace the call to bind() in the plugin with a call to on(). Note that this is not required; however, it is future-proof.
2) Remove the call to .stopPropagation in the declaration of the toggleIdleState function. Presumably, this may make it unfeasible to use multiple idle/active timers due to them bubbling up, but it will at least give you back the use of one for the entire document.
Somehow, calling .stopPropagation right after the creation of the event seems to have broken its usage on the element to which it is bound. I figure this is an unforeseen bug in jQuery 1.7.
Someone correct me if I'm wrong here.
How can i kill asp session when user was inactive
i am getting idle event, when mouse is active over a applet. How can this case be handled ?
@Brent
Hey Brent, thank you for your help but I can still not get this to work.
I have the reload script in index.html, that contains two other html's in Iframes (top.html in top Iframe and bottom.html and bottom Iframe).
According to firebug, document. is my top.html as opposed to my index.html.
I want to reload bottom, so i changed
handleUserEvent = function(){
top.$(top.document).trigger('keydown.idleTimer');
}
to
handleUserEvent = function(){
bottom.$(bottom.document).trigger('keydown.idleTimer');
}
but shouldn't this actually reference the index.html by using
parent.document?
bottom.document is showing as undefined for some reason.
Hi Paul,
thank you for your good work! It makes it more fun
I have one issue that I have sort of fixed but would like your view on: if a (mobile) device goes in sleep/suspend mode, the timer is also stopped. I use the timer to lock the screen after some time. However, if you have a timeout of, say, 10 min and the device goes to sleep after 5 min, then, if you wake it a day later, you can work on because the timeout has not fired. I now solve that by modifying your code to detect the time between user events. If that time is larger than the timeout I trigger the event. This is not ideal but better than nothing.
regards,
Mahatma
This looks like it's working for me to handle iFrames: