How to play sound in setInterval function? - javascript

I am trying to refresh the page and compare it to check if the table data is modified or not after interval..& if modified then play a notification sound.The notification sound duration is of 60 sec.But it play the sound for just a second & then it refresh the page.How can i pause the execution until the sound has been fully played & then continue.
var foo = setInterval(function(){
window.location.reload(1);
var myTable = document.getElementById('admin_id');
var rows = myTable.rows;
var firstRow = rows[0];debugger;
try {
if ($.cookie('new') === null || $.cookie('new') === "" )
{
$.cookie("new", firstRow["cells"][10].innerText);
}
else
{
var cookieValue = $.cookie("new");
if(cookieValue!=firstRow["cells"][10].innerText){
$.cookie("new", firstRow["cells"][10].innerText);
//clearInterval(foo);
document.getElementById('id_audio').play();
}
}
}catch(err){alert(err.message);};
}, 1800000);
//Audio TAg Code
<audio id="id_audio" src="sound.mp3" preload="auto"></audio>

When you reload the page, everything in the page (including your code) is thrown away and replaced by the new page. The code above after the reload call runs briefly (still on the old page), and when it returns the browser terminates any ongoing processes the page is doing and loads the page fresh. Your code does not wait at the reload for the page to reload and then keep going.
Instead of what you're doing, have your code that checks for the new cookie run on page load. Then when you're reloading, just reload — your code will run on the reloaded page (on load).
If you don't want the code run on every page load, but just on reloads, set a flag in session storage before reloading and check it on load:
When reloading:
sessionStorage.reloadedAt = Date.now();
location.reload(1);
Then on load:
if (+sessionStorage.reloadedAt > Date.now() - 30000) {
// Do your checks
}
3000ms = three seconds, adjust as appropriate.

Related

Keep the JS/jQuery code working in Safari when the tab is not active

I have a JS/jQuery code as shown below in which in which I want to keep the JS/jQuery code working when the session tab is not active.
The following code perfectly fine in Google Chrome but it doesn't work in Safari.
jQuery(document).ready(function ($) {
let lastActivity = <?php echo time(); ?>; // Line A
let now = <?php echo time(); ?>;
let logoutAfter = 3600; // page will logout after 1800 seconds if there is no activity
let userName = "<?php echo $_SESSION['user_name']; ?>";
let timer = setInterval(function () {
now++;
let delta = now - lastActivity;
console.log(delta); // Line A
if (delta > logoutAfter) {
clearInterval(timer);
//DO AJAX REQUEST TO close.php
$.ajax({
url: "/control/admin.php",
type: 'GET', // GET also fine
data: {action: 'logout', user_name: userName},
success: function (data) {
window.location.href = "admin.php";
},
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus);
}
});
}
}, 1000); //<-- you can increase it( till <= logoutAfter ) for better performance as suggested by #"Space Coding"
});
The value at Line A doesn't get incremented in Safari when the tab is not active but it works perfectly fine in Google Chrome. In Google Chrome, it works as expected.
You can replace counter (it counts seconds) with calculating time difference.
let lastActivity = new Date();
let logoutAfter = 3600;
...
let delta = (new Date()).getTime() - lastActivity.getTime();
if (delta > logoutAfter) {
...
}
P.S. So it must work even if the script itself is frozen when tab is inactive. Interval handler will be called at the moment when user activate this tab.
This approach will not work properly with multiple tabs opened. If user open new tab and started working in it, the earlier tab will logout the user as he is not active in that tab.
To overcome this, I will suggest to check the last active time from server using ajax call instead of doing it with javascript only.
According to this very thorough (but old) answer, setInterval() execution on inactive tabs is limited to max 1/s, on both Safari and Chrome - but not stopped. There are also plenty of questions here on SO about Javascript getting paused or de-prioritised on inactive tabs, some of which include solutions:
How can I make setInterval also work when a tab is inactive in Chrome?
iOS 5 pauses JavaScript when tab is not active
Safari JavaScript setTimeout stops when minimized
Chrome: timeouts/interval suspended in background tabs?
Probably the best option to do what you are trying is to use Web workers:
Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface.
There is an example of how to do that in an answer to one of the questions above.
But there is also a much simpler option, though you should evaluate if it is safe considering you are relying on this to log users out.
My testing of your code reflects the question I linked to earlier which describes setInterval() being slowed, but not stopped. For me, Safari (v 13.1, macOS 10.14.6) does not actually fully pause Javascript, but slows down execution of the loop, by increasing amounts. I see this by opening the dev console, and watching the output of the console.log(delta) messages - they slow right down, first running only every 2s, then 4s, and so on, though sometimes faster. But they do not stop.
That output also gives a hint about the problem, and the solution. The delta values shown on the console do not represent the real time difference since lastActivity. They are just incrementing numbers. If you see a delta value appear on the console 10 seconds after the last one, it should logically be +10, right? But it is not, it is just one higher.
And that's the problem here - the code is not counting the true time difference, it is just counting iterations of the loop:
let timer = setInterval(function () {
now++; // <-- problem
This code correctly sets now to the current time only if setInterval() runs exactly every second. But we know that when the tab is inactive, it does not. In that case it is just counting the number of times the loop runs, which has no relation to the real time elapsed.
To solve this problem, we have to determine now based on the real time. To do that, let's switch to using JS to calculate our timestamps (PHP is rendered only once, on page load, so if you use it inside the loop it will just stay fixed at the initial value):
// Note that JS gives us milliseconds, not seconds
let lastActivity = Date.now();
let now = Date.now();
let logoutAfter = 3600 * 1000;
let timer = setInterval(function () {
// PHP won't work, time() is rendered only once, on page load
// let now = <?php echo time(); ?>;
now = Date.now();
let delta = now - lastActivity;
console.log('New timer loop, now:', now, '; delta:', delta);
Now, even if there is a pause of 10s between iterations, delta will be the true measure of time elapsed since the page was loaded. So even if the user switches away to another tab, every time the loop runs, it will correctly track time, even if it doesn't happen every second.
So what does this mean in your case?
According to your report, JS is not running at all in the inactive tab. In that case, it can happen that the tab stays in the logged-in state, long past the time the user should have been logged out. However, assuming JS starts up again when you switch back the tab, the very first iteration of the loop will correctly calculate the time elapsed. If it is greater than your logout period, you will be logged out. So even though the tab stayed logged in longer than it should have, the user can't use it, since as soon as they switch to it they will be logged out. Note that "as soon" actually means "within 1 second plus the time it takes for the AJAX query to successfully log the user out".
In my testing, JS does not stop in an inactive Safari tab, but slows right down. In this case, it would mean that the user would be automatically logged out on the inactive tab, though not right at the time they should be. If the loop runs say every 8s, it could mean that the user would be logged out up to 7s later than they should have been. If iterations slow down even more, the delay can potentially be even more. Assuming JS starts up again as normal as soon as the user switches back the tab, behaviour will be exactly as above, the first iteration in that case will log them out.
EDIT
Here's simplified, complete code, and a JSFiddle showing it running and working.
jQuery(document).ready(function($) {
let lastActivity = Date.now();
let now = Date.now();
let logoutAfter = 3600 * 1000;
let timer = setInterval(function() {
now = Date.now();
let delta = now - lastActivity;
console.log('New timer loop, now:', now, '; delta:', delta);
if (delta > logoutAfter) {
alert('logout!');
}
}, 1000);
});

How can I do a javascript that only runs once

I have this jquery code:
$(document).ready(function(){
$(".body").hide();
setTimeout(function() {
$(".body").show()
}, 2000);
setTimeout(function() {
$(".img").fadeOut(1000)
}, 1000);
});
And I'd like it so that it will only work when the page is first clicked on. So when you reload the page or navigate through the site and navigate back to it the script above won't execute.
You can use localStorage to store values at the browser level, so next time a user visits your site they will get the same data. If you set a flag when they visit your site then you can tell the first time they visit, due to that flag not being set.
Here's that change added to your code, with corresponding comments...
$(document).ready(function(){
// check localStorage to see if we've run this before. If we have then do nothing
if (!localStorage.getItem("first-run")) {
// set a flag in localStorage so we know we've run this before.
localStorage.setItem("first-run", true);
$(".body").hide();
setTimeout(function() {
$(".body").show()
}, 2000);
setTimeout(function() {
$(".img").fadeOut(1000)
}, 1000);
}
});
Try something like this.
$(document).ready(function() {
if(!localStorage.visited) {
//do first page load stuff
...
localStorage.visited = true;
}
});
There are already solutions here using localStorage; however, a value set in localStorage will remain until the user clears their browser data. This means that your code will never run again unless you specifically do extra work to check how long it has been set, etc.
If you would like it to run again when they visit the page later you should use sessionStorage:
...data stored in sessionStorage gets cleared when the page session
ends. A page session lasts for as long as the browser is open and
survives over page reloads and restores. Opening a page in a new tab
or window will cause a new session to be initiated, which differs from
how session cookies work.
This will allow the code to run on a new visit to the page, but reloading or navigating away/back will not trigger it because the sessionStorage is still set. However, if they close the tab/window and come back to it later, the code will run again.
$(document).ready(function() {
if(!sessionStorage.visited) {
sessionStorage.visited = true;
...
//other code
}
});

How to reload page when jquery.counter trigger finish.countdown event for multiple instance?

I am using multiple instance for jQuery countdown and implement page reload when counter get finished
E.g.
$('.countdown').each(function() {
var $this = $(this),
finalDate = $(this).data('countdown');
$this.countdown((finalDate), function(event) {
var days = event.strftime('%D');
$(this).find('.days').children('span').html(days);
$(this).find('.hours').children('span').html(event.strftime('%H'));
$(this).find('.minutes').children('span').html(event.strftime('%M'));
$(this).find('.seconds').children('span').html(event.strftime('%S'));
});
$(this).on('finish.countdown', function(event){
/*if(!window.location.hash && !(window.location.hash.indexOf('_loaded') > -1)) {
window.location = window.location + '#_loaded'; window.location.reload();
}*/
//If I put window location reload here it will goes into infinite loop. Also above commented code will reload page twice initially which is also not valid solution.
});
});
Issue: If countdown is already finished (E.g. 00:00:00:00 ) then page reload occur twice when script loaded at first time,
I have used localStorage concept but unable to find exact solution. Please help
I had almost this issue with page constantly reloading instantly.
Try and check if your local time and server time are the same. In my case, the difference was two hours, which was the issue that put the page into constant loop.
Countdown plugin has some notes on timezone awareness: http://hilios.github.io/jQuery.countdown/examples/timezone-aware.html

Refresh just home page

I am currently designing a system which includes a homepage that show the person who logs in only the work they have to do. I have been asked to set up this homepage to refresh every 3 minutes which I have done using this code:
function startTimer() {
var now = new Date();
var minutes = now.getMinutes();
var seconds = now.getSeconds();
var secTime = minutes*60*seconds;
if(secTime % (3*60) == 0){
var refreshTime = 3*60*1000;
} else {
var refreshTime = (secTime % (3*60)) * 1000;
}
setTimeout('refresh()', refreshTime);}
function refresh() {
window.location.href = 'myURL';
}
startTimer();
The problem I currently have is that when I navigate away from this page, but still in the system, it keeps returning me to homepage and I lose what I am working on.
Is there a way that I can keep refreshing homepage for those who haven't moved away from it and stop it when someone does?
I am very new to Javascript so please be patient if I ask a lot of question.
Thank you in advance for any help given.
I assume you are using a shared javascript file on all pages of the site which is why the timer will keep running on every page. You could make sure that the timer only runs on the homepage by checking the page url and wrap your startTimer function inside this check:
if (document.location.href == "http://www.yourhomepage.com"){
startTimer();
}
Replace http://www.yourhomepage.com with whatever url your homepage is on. This will only work if your pages are separate html files. If you are using a hashbang method whereby the document doesn't change, this will not work.
You can use Ajax to refresh the work log part of the page instead of refreshing the whole page.
When you refresh your page, your code redirect you to your home page because of window.location.href = 'myURL';. The location change, and it redirect you everytime to 'myURL'.
You would like to refresh only a part of your page. You have to send a XMLHttpRequest or Ajax request ( you load a page into your current page without reloading your current page ). https://developer.mozilla.org/fr/docs/XMLHttpRequest
When you get the page loaded, you insert the text loaded into the page.
Then, call the function which send request, every "refreshTime" like that
function sendAjax(){
// ... ajax request
// refreshTime = 3 * 60 * 1000;
setTimeout( sendAjax, refreshTime );
}
sendAjax();
Don't use quote arround the function name in setTimout. setTimemout need a function to call (not his name but his value) and time parameters.

Is it possible to know how long a user has spent on a page?

Say I've a browser extension which runs JS pages the user visits.
Is there an "outLoad" event or something of the like to start counting and see how long the user has spent on a page?
I am assuming that your user opens a tab, browses some webpage, then goes to another webpage, comes back to the first tab etc. You want to calculate exact time spent by the user. Also note that a user might open a webpage and keep it running but just go away. Come back an hour later and then once again access the page. You would not want to count the time that he is away from computer as time spent on the webpage. For this, following code does a docus check every 5 minutes. Thus, your actual time might be off by 5 minutes granularity but you can adjust the interval to check focus as per your needs. Also note that a user might just stare at a video for more than 5 minutes in which case the following code will not count that. You would have to run intelligent code that checks if there is a flash running or something.
Here is what I do in the content script (using jQuery):
$(window).on('unload', window_unfocused);
$(window).on("focus", window_focused);
$(window).on("blur", window_unfocused);
setInterval(focus_check, 300 * 1000);
var start_focus_time = undefined;
var last_user_interaction = undefined;
function focus_check() {
if (start_focus_time != undefined) {
var curr_time = new Date();
//Lets just put it for 4.5 minutes
if((curr_time.getTime() - last_user_interaction.getTime()) > (270 * 1000)) {
//No interaction in this tab for last 5 minutes. Probably idle.
window_unfocused();
}
}
}
function window_focused(eo) {
last_user_interaction = new Date();
if (start_focus_time == undefined) {
start_focus_time = new Date();
}
}
function window_unfocused(eo) {
if (start_focus_time != undefined) {
var stop_focus_time = new Date();
var total_focus_time = stop_focus_time.getTime() - start_focus_time.getTime();
start_focus_time = undefined;
var message = {};
message.type = "time_spent";
message.domain = document.domain;
message.time_spent = total_focus_time;
chrome.extension.sendMessage("", message);
}
}
onbeforeunload should fit your request. It fires right before page resources are being unloaded (page closed).
<script type="text/javascript">
function send_data(){
$.ajax({
url:'something.php',
type:'POST',
data:{data to send},
success:function(data){
//get your time in response here
}
});
}
//insert this data in your data base and notice your timestamp
window.onload=function(){ send_data(); }
window.onbeforeunload=function(){ send_data(); }
</script>
Now calculate the difference in your time.you will get the time spent by user on a page.
For those interested, I've put some work into a small JavaScript library that times how long a user interacts with a web page. It has the added benefit of more accurately (not perfectly, though) tracking how long a user is actually interacting with the page. It ignore times that a user switches to different tabs, goes idle, minimizes the browser, etc.
Edit: I have updated the example to include the current API usage.
http://timemejs.com
An example of its usage:
Include in your page:
<script src="http://timemejs.com/timeme.min.js"></script>
<script type="text/javascript">
TimeMe.initialize({
currentPageName: "home-page", // page name
idleTimeoutInSeconds: 15 // time before user considered idle
});
</script>
If you want to report the times yourself to your backend:
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","ENTER_URL_HERE",true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpentOnPage);
TimeMe.js also supports sending timing data via websockets, so you don't have to try to force a full http request into the document.onbeforeunload event.
The start_time is when the user first request the page and you get the end_time by firing an ajax notification to the server just before the user quits the page :
window.onbeforeunload = function () {
// Ajax request to record the page leaving event.
$.ajax({
url: "im_leaving.aspx", cache: false
});
};
also you have to keep the user session alive for users who stays long time on the same page (keep_alive.aspxcan be an empty page) :
var iconn = self.setInterval(
function () {
$.ajax({
url: "keep_alive.aspx", cache: false });
}
,300000
);
then, you can additionally get the time spent on the site, by checking (each time the user leaves a page) if he's navigating to an external page/domain.
Revisiting this question, I know this wouldn't be much help in a Chrome Ext env, but you could just open a websock that does nothing but ping every 1 second and then when the user quits, you know to a precision of 1 second how long they've spent on the site as the connection will die which you can escape however you want.
Try out active-timeout.js. It uses the Visibility API to check when the user has switched to another tab or has minimized the browser window.
With it, you can set up a counter that runs until a predicate function returns a falsy value:
ActiveTimeout.count(function (time) {
// `time` holds the active time passed up to this point.
return true; // runs indefinitely
});

Categories

Resources