I have a program which uses eventStart: new Date.getTime(); when the document is loaded and when user completes some section and click continue to go to next section I have setup the function to track the end time getting the eventEnd: new Date.getTime(); now I fall in to a unique situation to track the idle Time for so I can properly calculate the total time taken by the user to finish the section. Any help or documentation regarding this would be appreciated.
Thanks.
Depends on what you are calling idle time.
Check for user activity
You can use the mousemove event on the document.body and see if the user is interacting with the page at all. (I'd also check for tap and keyboard events, as users can scroll that way too.)
This can't, however, detect if the user is sitting there reading something without touching mouse or keyboard.
Is this tab the current one
There is a recommended API to see if the current window/tab is active, but that has limited support. There is a discussion here.
Related
Is there any mechanism that would allow me handle the values on a browser level? What I mean is either:
sessionStorage that I can access values in ANY tab in browser (something like server side sessions)
localStorage that would be removed on session end (when closing the browser, not tab)
For example, the video starts in player in one tab. Some flag is stored in that kind of storage. When user opens another tab with the same URL, app should read that flag and dissalow playing the video. Of course it should be removed on exit, otherwise flag would dissalow all the future requests in that browser. Any suggestions?
every tab or window data can save/read to local/session storage but it's limited to that domain only.
The question that you asked about video handling over two tabs, it can be pulled of, but that is very tricky to handle, and I would not suggest to go that road! You can periodicaly save timestamps of video to browser storage but it also depends on server that is sending the video to browser, and you could end up not serving the video to the user at all!
For clearing the data when browser window close I think there is no event for that but there is event for window loosing focus so you can use that I guess.
hth,
$(window).on('beforeunload', function DecideAction() {
if (('localStorage' in window) && window['localStorage'] !== null) {
//get value from localstorage using getItem and allow/deny the further access
}
});
If the requirement is to have this last "as long as the browser window is open", you're going to hit repeated issues as browsers don't work on that level any more - there is tab-level and domain-level (persists like cookies). The "Browser Window" is just a collection of tabs, unless you specifically set up your browser in a certain way (to remove cookies and session data on closing and not share data between window instances). This however is browser setup (and isn't even standard across different browsers), and not something you can control client-side.
If you're willing to consider some alternatives that will provide the end result you seem to require, if not in the specific manner you have specified, read on:
To Expand on AkshayJ's original comment, use localStorage as sessionStorage is only ever tab-specific (it can't be shared).
In order to clear the flag, as part of the same functionality that sets the flag, add an onunload event to the tab playing the video that will clear it when the tab is closed or the window location moves away from the video. This will allow greater functionality than you originally requested, because in your original case the user would have to close down the browser entirely before they could play the video again, even if the tab that was playing the video was long gone or had moved on to another page.
UPDATE:
If the security/authorization around this is of paramount importance (rather than just wanting to stop it happening "by accident"), then using localStorage is completely the wrong approach - this data and its existence is ultimately controlled by the user. They can remove it, or set up their browser so that window instances don't share the data, so all they need to do is open a new window to view your video twice at the same time. A determined user would find their way around this in minutes.
If you want to control it absolutely, you have to take this domain side rather than relying on browser storage, and use some other tag like a list of currently-accessing IPs, or some other method of identifying a unique user, to determine whether the video can be played or not. Bear in mind that you would have the same issues as before regarding when to clear the flag whether it's browser side of domain side.
UPDATE:
re: what event to use, it appears that onunload and onbeforeunload are both fully supported across all common browsers (ref: Here and Here). This Answer recommends using both in order to be on the safe side.
UPDATE:
The OP has expressed worry that unload events are unreliable and that the user might remain locked out forever if something goes wrong. Personally I haven't experienced any unreliability here, but if you're worried, then introduce a timeout aspect. Have the tab playing the video update the flag (wherever it is stored) with a timestamp every 30 seconds/1 minute/whatever. Then when a new instance of the page loads, have it check the timestamp. if something has happened to the existing page such that it froze and unload events didn't run, the timestamp will be out of date because it will have also stopped updating, so you just have to check whether the timestamp is out of date as well as checking for presence.
Finally I gave up of the server side sessions because it raised other issues, and solved it with this workflow:
After page load, localStorage value is set if it hasn't been before, as well as flag that the player is opened in this tab. If the localStorage is already set, flag is set to false.
If flag is set, play video, otherwise prohibit.
On page unload, only if the flag is set (that is, if user opened video in this tab), remove localStorage value.
$(function () {
if (localStorage.playerTabOpened) {
var dateNow = Date.now();
var diffSinceLastTabOpened = (dateNow - localStorage.playerTabOpened) / 1000;
// if playerTabOpened value was stored more than 1 day ago, delete it anyway because it could be left by chance
if (diffSinceLastTabOpened > 86400) {
localStorage.removeItem("playerTabOpened");
};
}
if (!localStorage.playerTabOpened) {
shared.playerTabOpenedHere = true;
localStorage.setItem("playerTabOpened", Date.now());
} else {
shared.playerTabOpenedHere = false;
}
});
$(window).on("beforeunload", function () {
if (shared.playerTabOpenedHere) {
localStorage.removeItem("playerTabOpened");
}
});
if (shared.playerTabOpenedHere) {
// play
} else {
// throw error
}
Using JavaScript (and/or jQuery), Is it possible to pause the user from exiting a page for a set amount of time without showing an alert/confirmation?
(Say the user clicks on a different page or closes the window, a timer should start for three seconds [during which time something happens] and then the next page is loaded or the window closes.)
No, it is impossible in modern browsers.
(Moreover, think of how annoying that would be if every popup did that)
The closest you can do is show the dialog using onbeforeunload but you have asked to avoid this.
But why would you want to do that?
Worth mentioning, that this is a magical time. You might want to report something to the server but you suddenly can't because the user is leaving. This is one of those times things that are usually considered bad practice like synchronous ajax might make sense.
No. This is not possible. At best you can implement an onbeforeunload handler but your options at this point are very limited (you can certainly not 'wait 3 seconds').
Browsers will try to protect the user so this is behavior that browsers enforce and they have incentive to enforce it.
This works in chrome and firefox:
window.onbeforeunload = function() {
var now = new Date();
while( new Date() - now < 3000 );
};
It will also drain battery, so you are killing 2 birds with one stone.
I have this functionality built in Jquery/ javascript where a user is notified when their session is about to be timed out. Then they are given an option to extend it. If they don't make a choice the pop up closes itself and the browser is redirected to the login page. It worked perfectly fine for a while. But now I noticed it works correctly only if I am active on the computer. If the computer is left unattended for an entire day, the pop up does not begin the countdown until the user unlocks the computer and logs in again.
Is anybody aware of this behavior where ie stops executing javascript when the computer is left unattended for a long time?
Update: Is there a way to keep the tab from sleeping? Without that, the browser won't be able to redirect at the right time.
setTimeout only works when the tab is active. In some browsers even changing tab will make it stop counting. So not only if you are on the computer but if you're not on the specific page it might not work. Also on mobile devices with multitasking it's bound to fail, forget about tabs, applications often go to suspended mode.
Take a look at this question, it offers the same solution as Luka with a code example:
How can I make setInterval also work when a tab is inactive in Chrome?
You might want to do two checks on the time passed, one to check if you need to show the popup, and one to close the popup, using the total time passed instead of having a different count down.
i would suggest logging the current time when the page is loaded and then calling a function every 10 seconds of so that checks if the time passed is more than x amount, the reason your problem occurs is most likely because the default timeout function only counts down while the page is being rendered.
Alright, I've found a bunch of answers concerning native functions like window.onblur and window.onfocus... But they won't help so I'd like to be more specific
Say you open several tabs of one website
Say you receive a message and there's a sound to announce the message
As you have several tabs opened, you will hear the sound the number of opened tabs. Which makes a how'd'u'callit symphony
Best solutions I've found so far, but which don't work
1. window.onfocus and window.onblur
2. Play sound if var infocus evaluates to true, don't play if not
3. It is crossbrowser
4. It is simple
5. It does not work
Why the best solution won't work? Say you switch focus to another tab of a different website, your website loses focus so you won't hear the sound. Even worse, say you switch to another program, then the browser itsel loses focus and you won't hear the sound
So what shall I do?
You could save the timestamp of the last onFocus() event in a JavaScript variable and in a cookie (access set to your website root). Then when you want to play the alert sound, you compare the current values of the variable and the cookie and only play the sound if those two match.
Alright, two weeks after it seems like I've found the real solution. Which actually proves that if you want to do something, don't ask for help, just do it
This is what I did:
Create a cookie with a randon id and the current time (winid + t1). The cookie is created by each opened tab on loading.
document.cookie = 'winid='+winid+t1;
Create a function which will update the current time in the set cookie, say, every 3 seconds (I kindda don't like to overflow clients, so it's 3 secs not 1). If the function finds out that the winid in the cookie and the winid of the current tab don't match and 3 secs have elapsed, then the tab was closed, redefine the primary tab inside the same function.
window.setInterval(setwinid,3000);
This is it, every time you need to, say, play a sound, you should check first, whether it is the tab which is to play it
The trick is that each tab has its own winid. But only one winid is stored in cookie, is updated and thus allows the one tab to perform actions. Pretty simple. I actually started using this method for updating messages in the box across all tabs not only for playing music
One solution would be to have a server-side solution that would play the notification only once. You don't specify how the site receives the messages, but I assume it's some form of AJAX call that gets the message from the server and the messages are saved in a database.
Add a flag to the database that signifies that the message has been sent. Set the flag the first time the user's browser queries for new messages. On the page itself play the sound only if the flag has not been set, otherwise don't play the sound. Now only the first page that fetches the message will play the sound.
I'm trying to get add a delay of 1000ms before a person leaved the page. I'm using the beforeunload event to start a jquery animation and would like it to finish before the page leaves.
I'm not concerned with older browsers, IE9, latest safari, chrome and FF4 are all i'm interested in.
Edit: Well I was hoping to implement it when just navigating internal pages. Sure I can make all my internal links a javascript call, but I would have preferred a less brute force method.
Also, I'm not stopping people from leaving the page, not even making them wait a huge long time, 1 second for a fade out? Thats no worse than every game I play fading out when I select quit.
Now had I asked how do I prevent a person from leaving a page, then yes all the "don't do it" would have been deserved.
Firstly, if people want to leave your page, don't put any barriers or difficulties in leaving it. Just let them.
Konerak said it well...
Using a blocking action is acceptable when the user is about to lose data by leaving the page, but using them for animations and gimmicks will quickly annoy your users.
Secondly, you can only prevent automatic closing with a blocking action, such as an alert() or prompt(), which temporary blocks the browser's viewport, waiting for user response.
jsFiddle.
Well I was hoping to implement it when just navigating internal pages.
I know it’s four years later now, but I wanted to point out that, within the bounds you’ve described, you can do this.
$(document).on("click", "a", function (e) {// Listen for all link click events on the page (assuming other scripts don’t stop them from bubbling all the way up)
// Stop the link from being followed.
e.preventDefault();
// Grab the link element that was clicked
var linkClicked = e.target;
// I'm using setTimeout to just delay things here, but you would do your animation and then call a function like this when it’s done
window.setTimeout(function () {
// Simulate navigation
window.location = linkClicked.href;
}, 1000);
return false;
});
It’s still inadvisable:
I suspect it would get annoying to users pretty quickly
Without additional code, this would prevent users from command/control-clicking to open links in a new tab.
8 years later and I'm about to code this for my own website, specifically as a fade between pages. But I'm only going to do this for navigating between pages within my site, and I'm not going to use window.onbeforeunload or window.onclick. I attach a click event handler to specific "buttons" on each page. pointer-events is even disabled for other elements, so the event's element scope is very limited. The code is a switch() statement with cases for each "button". Each button navigates to a specific page within the site.
I don't think this is bad web page or web site behavior. A 1 second delay when transitioning between pages is not going to annoy users. I think you might be able to get 2 seconds or more out of it, if you include the time it takes to load the destination page, which can also fade in gradually in as it loads data.
It's visually elegant, especially compared to typical news/info sites with flex layouts that shift all over the page while they load. Those pages spend 2 or more seconds shifting stuff around before you can read anything.
My site is already filled with CSS and SVG animations, so adding this to the internal page navigation is no sweat for this project. If you limit the element scope of the user events and you make the delays small, this is good behavior, not bad behavior, IMO. Visual elegance has value.
EDIT- As I get into it, I see that for one group of similar pages I can achieve better cross-fading between them by consolidating them into one page. That way I can truly cross-fade between each sub-page instead of fading out one page then fading in another.