I have an application that needs to be timed out after 28 minutes. It will show the jQuery dialog for 2 minutes. If the user clicks "Ok" within the two minutes the timer refreshes to 28 minutes and when the count down reaches 0 minutes it should show the jQuery dialog again.
The issue is when I debug, I see the timeout variable is not clearing out the timeout. After I click "Ok", the timer resets to 28 minutes but the setTimeout doesn't show the dialog again when the count down reaches 0 minutes.
Here is my code:
var timeout;
function timer() {
countDownDate = 0;
console.log("Hello");
countDownDate = 0;
var timeExpires = new Date().getTime();
countDownDate = timeExpires + 1680000;
now = 0;
distance = 0;
if(timeout){
clearTimeout(timeout);
}
// Update the count down every 1 second
var x = setInterval(function () {
// Get todays date and time
now = new Date().getTime();
// Find the distance between now an the count down date
distance = countDownDate - now;
// Time calculations for days, hours, minutes and seconds
var days = Math.floor(distance / (1000 * 60 * 60 * 24));
var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
var seconds = Math.floor((distance % (1000 * 60)) / 1000);
if (distance < 0) {
if ($("#alert").length) {
var title;
if ($("#alert span").length) {
title = $("#alert span").text();
}
$("#alert div").dialog({
title: title,
modal: true,
buttons: {
Ok: function() {
var foo = $(this);
clearTimeout(timeout);
timer();
foo.dialog('close');
},
Cancel: function() {
esriId.destroyCredentials();
window.location.replace(redirect_uri);
}
}/*,
open: function() {
var foo = $(this);
timeout = setTimeout(function() {
foo.dialog('close');
esriId.destroyCredentials();
window.location.replace(redirect_uri);
}, 120000);
},*/
});
}
timeout = setTimeout($("#alert div").dialog("open"), 120000);
clearInterval(x);
}
}, 1000);
};
Here is the HTML div for the alert:
<div id="alert" style="display:none">
<span>You will be signed out</span>
<div>You will be signed out due to inactivity on the page. If you wish to stay on the page, please press 'Ok'</div>
</div>
As written,
setTimeout()
command is wrongly constructed.timer()
.timer()
can be simplified by :
timer()
.timer()
.if (distance < 0)
etc in the time display function.Here's the revised code :
// set up the dialog
function showDialog(callback) {
$("#alert div").dialog('destroy').dialog({
title: $("#alert span").length ? $("#alert span").text() : '---',
modal: true,
buttons: {
Ok: function() {
$(this).dialog('close');
callback('ok')
},
Cancel: function() {
// $(this).dialog('close'); // ?
callback('cancel');
}
}
}).dialog('open');
}
// function for calculating and displayig the countdown values
function displayCountdown(t) {
var distance = Math.max(0, t - Date.now());
var days = Math.floor(distance / (1000 * 60 * 60 * 24));
var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
var seconds = Math.floor((distance % (1000 * 60)) / 1000);
// ... display days, hours, minutes, seconds somewhere
}
// object which defines the three timers
var timers = {
'ticker': { 'ref': null, 't': 1000 }, // 1 second
'stopTicker': { 'ref': null, 't': 1680000}, // 28 minutes
'cancelDialog': { 'ref': null, 't': 120000 } // 2 minutes
}
function redirect() {
esriId.destroyCredentials();
window.location.replace(redirect_uri);
}
//
function timer() {
clearInterval(timers.ticker.ref);
clearTimeout(timers.stopTicker.ref);
clearTimeout(timers.cancelDialog.ref);
timers.stopTicker.ref = setTimeout(function() {
clearInterval(timers.ticker.ref);
showDialog(function(outcome) {
if(outcome === 'ok') {
timer();
} else {
redirect();
}
});
timers.cancelDialog.ref = setTimeout(redirect, timers.cancelDialog.t);
}, timers.stopTicker.t);
timers.ticker.ref = setInterval(displayCountdown.bind(null, Date.now() + timers.stopTicker.t), timers.ticker.t);
};
Note that redirect()
will be called in two possible ways :
The callback passed to showDialog()
isn't strictly necessary but allows the dialog to be completely agnostic of the consequences of its outcome. All that logic is in the caller, timer()
.
Another, arguably cleaner, approach is to promisify the dialog.
Here, everything remains the same as above except showDialog()
and timer()
.
// set up a promisified dialog
function showDialog() {
return $.Deferred(function(dfrd) {
$("#alert div").dialog('destroy').dialog({
'title': $("#alert span").length ? $("#alert span").text() : '---',
'modal': true,
'buttons': {
'Ok': dfrd.resolve, // yay!
'Cancel': dfrd.reject // yay!
}
}).dialog('open');
}).always(function() {
$("#alert div").dialog('close');
});
}
function timer() {
clearTimeout(timers.ticker.ref);
clearTimeout(timers.stopTicker.ref);
clearTimeout(timers.cancelDialog.ref);
timers.stopTicker.ref = setTimeout(function() {
clearInterval(timers.ticker.ref);
$.Deferred(function(dfrd) { // "race" pattern
showDialog().then(dfrd.resolve, dfrd.reject);
timers.cancelDialog.ref = setTimeout(dfrd.reject, timers.cancelDialog.t);
}).then(timer, redirect); // yay-yay!
}, timers.stopTicker.t);
timers.ticker.ref = setInterval(displayCountdown.bind(null, Date.now() + timers.stopTicker.t), timers.ticker.t);
};