Add event to prevent timeout inside Inappbrowser - javascript

I have a timeout function
var idleTimeOut = 60; // 1 minute
ResetIdleSecondsEvent = function () {
// Reset counter for all listed event
$(document).on("click mousemove keypress touchstart touchend touchcancel touchmove", function () {
_idleSecondsCounter = 0;
})
}
function VerifyTimeOutInterval() {
// Run every seconds to call function and check if current counter is more than
// the preset time
window.setInterval(CheckIdleTime, 1000);
}
function CheckIdleTime() {
// Check timer only predefined timeout value is not 0, null or empty
if (idleTimeOut != "") {
// Increase counter for seconds
_idleSecondsCounter++;
// Check if current counter is more than the preset timeout period
if (_idleSecondsCounter >= idleTimeOut) {
// Notify user that he/she has been automatically logged out
navigator.notification.alert("You have been automatically logged out due " +
"to inactivity. Please login again.", function () { }, "Logged Out", 'OK');
// Navigate to login page
self.navigateLogout();
}
}
}
This works great in my application when user do nothing for 1 minutes, timeout message will appear and take user to login screen.
But when user open an external link using Inappbrowser and has activity, the idle seconds did not get reset, the timeout message appear and take user back to login. So how do I add the same code into Inapp browser?
As far as I know, the Inappbrowser only has the event loadstart, loadstop, loaderror and exit. I tried the following code to add event into Inappbrowser but no luck.
var inappBrowserObj = window.open(url, '_blank', 'location=yes');
inappBrowserObj.addEventListener('loadstop', ResetIdleSecondsEvent());
inappBrowserObj.addEventListener('loadstop', VerifyTimeOutInterval());
Please tell me what is the correct way to handle timeout function inside Inappbrowser.
Thanks

Your code seems to be wrong while implementing the event handlers. Your callbacks are incorrectly passed and also you don't need to register handlers for same event twice (though you can but not required). Your code should be:
inappBrowserObj.addEventListener('loadstop', ResetIdleSecondsEvent);
Observe how I have passed the callback, your code will execute that function instead of passing it as a callback.
Make your other function calls within the ResetIdleSecondsEvent function.
I hope this helps.

Related

Using Settimeout to warn and finally redirect user for inactive session not working

Idea is to give a warning to user that session is going to timeout if idle for 15 minutes and redirect to home page after 20 minutes(requirement is not to log off the user).
Currently after 15 minutes the warning comes up. I am waiting for the next five minutes, but the next alert doesn't come up.
Please help me out in understanding on what I have written wrong here. Is the alert message to be done via use of modal?
var sessionTimoutWarning = 900000; // Display warning in 15 Min.
var sessionTimout = 1200000; // Redirect in 20 minute.
var sessionsessionWarningTimer;
var sessionsessionTimeoutTimer;
// Start timers.
function StartTimers() {
sessionWarningTimer = setTimeout("IdleWarning()", sessionTimoutWarning);
sessionTimeoutTimer = setTimeout("IdleTimeout()", sessionTimout);
}
// Reset timers.
function ResetTimers() {
clearTimeout(sessionWarningTimer);
clearTimeout(sessionTimeoutTimer);
StartTimers();
}
// Show idle timeout warning dialog.
function IdleWarning() {
// Logout the user.
var toContinueSession = confirm("Warning:Session is going to expire in next 5 minutes due to inactivity. Press Ok to continue. Please save the changes made.");
if (toContinueSession) {
ResetTimers();
} else
window.location.replace("../Default.aspx");
}
function IdleTimeout() {
alert("Session has already expired. Redirecting to Home Page.");
window.location.replace("../Default.aspx");
}
<body style="max-width: 100%; height: 100%;" onload="StartTimers();">
Edit: I am resetting the timer if user wants to continue by clicking Ok when the warning alert is poped up. What I am expecting is after the alert message is poped up and user is still working on something else (not coming on this page), after 5 minutes the second popup should come up stating that session is already expired i.e. IdleTimeout() getting called, which is not happening.
I think the problem is that you are calling ResetTimers(); in IdleWarning(), and this is cancelling the sessionTimeoutTimer.
Look at the code:
...
if (toContinueSession) {
ResetTimers();
} ...
And:
// Reset timers.
function ResetTimers() {
clearTimeout(sessionWarningTimer);
clearTimeout(sessionTimeoutTimer);
StartTimers();
}
You restart the 20 minute timer if the user clicks OK on the alert. If they do not click OK then they are immediately redirected, so your timeout code can never execute.
I'm presuming that even if the user clicks OK you do not want to restart the sessionTimeoutTimer, as that should still trigger after the 20 minute deadline.
Edit following OP comment
I now understand that you are concerned that the sessionTimeoutTimer does not execute if the user has not noticed the alert popup.
Unfortunately, browser dialogs are modal and they freeze underlying timers: your sessionTimeoutTimer will not execute if an alert or confirm popup is open.
There is no way to override this behaviour using the standard alert or confirm popup - it is built in to the browser and cannot be changed.
As an alternative, you could implement your own popup dialog instead of using alert, which will therefore not block the timer from running. I cannot think of an alternative way of resolving this issue.
Your problem is a type for the variable sessionTimoutWarning since you actually declare it as sessionsessionTimoutWarning but use it as sessionTimoutWarning (one session). You should also use the actual function objects rather than surround them in strings when calling timeouts. i.e.
setTimeout(IdleWarning, sessionTimoutWarning);
compared to
setTimeout("IdleWarning()", sessionTimoutWarning);
Try this:
sessionsessionTimoutWarning = 900000; // Without "var" - make global
sessionTimout = 1200000; // Without "var" - make global
OR Method #2:
window.sessionsessionTimoutWarning = 900000; // Without "var" - make global
window.sessionTimout = 1200000; // Without "var" - make global
usage:
//..
console.log(window.sessionTimout); // make sure is available
Then replace alert with console.log
ex.
console.log("Session has already expired. Redirecting to Home Page.");
Debug with console log if everything is fine.
Try this , I have modified some part
var sessionTimoutWarning = 900000; // Display warning in 15 Min.
var sessionTimout = 1200000; // Redirect in 20 minute. //change this to 5 min
var sessionsessionWarningTimer;
var sessionsessionTimeoutTimer;
// Start timers.
function StartTimers() {
sessionWarningTimer = setTimeout("IdleWarning()", sessionTimoutWarning);
}
function EndSession() //this will end the complete session
{
sessionTimeoutTimer = setTimeout(IdleTimeout(){
window.location.replace("../Default.aspx");
}, sessionTimout);
//redirect to the page in this function
}
// Reset timers.
function ResetTimers() {
clearTimeout(sessionWarningTimer);
// clearTimeout(sessionTimeoutTimer);
StartTimers();
}
// Show idle timeout warning dialog.
function IdleWarning() {
// Logout the user.
var toContinueSession = confirm("Warning:Session is going to expire in next 5 minutes due to inactivity. Press Ok to continue. Please save the changes made.");
if (toContinueSession) {
//here you get the event after the 15 min .
ResetTimers();
} else
{
// if he didn't continue then, call the session clear function
EndSession() //but in this changes have tge timer is 5 min because already 15 is completed .
}
}
function IdleTimeout() {
alert("Session has already expired. Redirecting to Home Page.");
}
<!-- language: lang-html -->
<body style="max-width: 100%; height: 100%;" onload="StartTimers();">
<!-- end snippet -->

How setInterval and setTimeout behave on Phonegap/Cordova when app resumes from background? [duplicate]

I have a jQuery Mobile web app which targets iOS and Android devices. A component of the application is a background task, which periodically checks for a.) changes to local data and b.) connectivity to the server. If both are true, the task pushes the changes.
I'm using a simple setTimeout()-based function to execute this task. Each failure or success condition calls setTimeout() on the background task, ensuring that it runs on 30 second intervals. I update a status div with the timestamp of the last task runtime for debugging purposes.
In any desktop browser, this works just fine; however, on iOS or Android, after some period of time, the task stops executing. I'm wondering if this is related to the power conservation settings of the devices--when iOS enters stand-by, does it terminate JavaScript execution? That is what appears to happen.
If so, what is the best way to resume? Is there an on-wake event which I can hook into? If not, what other options are there which don't involve hooking into events dependent on user interaction (I don't want to bind the entire page to a click event just to restart the background task).
Looks like Javascript execution is paused on MobileSafari when the browser page isn't focused. It also seems if setInterval() events are late, they are simply fired as soon as the browser is focused. This means we should be able to keep a setInterval() running, and assume the browser lost/regained focus if the setInterval function took much longer than usual.
This code alerts after switching back from a browser tab, after switching back from another app, and after resuming from sleep. If you set your threshold a bit longer than your setTimeout(), you can assume your timeout wouldn't finish if this fires.
If you wanted to stay on the safe side: you could save your timeout ID (returned by setTimeout) and set this to a shorter threshold than your timeout, then run clearTimeout() and setTimeout() again if this fires.
<script type="text/javascript">
var lastCheck = 0;
function sleepCheck() {
var now = new Date().getTime();
var diff = now - lastCheck;
if (diff > 3000) {
alert('took ' + diff + 'ms');
}
lastCheck = now;
}
window.onload = function() {
lastCheck = new Date().getTime();
setInterval(sleepCheck, 1000);
}
</script>
Edit: It appears this can sometimes trigger more than once in a row on resume, so you'd need to handle that somehow. (After letting my android browser sleep all night, it woke up to two alert()s. I bet Javascript got resumed at some arbitrary time before fully sleeping.)
I tested on Android 2.2 and the latest iOS - they both alert as soon as you resume from sleep.
When the user switches to another app or the screen sleeps, timers seem to pause until the user switches back to the app (or when the screen awakens).
Phonegap has a resume event you can listen to instead of polling for state (as well as a pause event if you want to do things before it is out of focus). You start listening to it after deviceReady fires.
document.addEventListener("deviceready", function () {
// do something when the app awakens
document.addEventListener('resume', function () {
// re-create a timer.
// ...
}, false);
}, false);
I use angular with phonegap and I have a service implemented that manages a certain timeout for me but basically you could create an object that sets the timer, cancels the timer and most importantly, updates the timer (update is what is called during the 'resume' event).
In angular I have a scopes and root scope that I can attach data to, my timeout is global so I attach it to root scope but for the purpose of this example, I'll simply attach it to the document object. I don't condone that because you need should apply it to some sort of scope or namespace.
var timeoutManager = function () {
return {
setTimer: function (expiresMsecs) {
document.timerData = {
timerId: setTimeout(function () {
timeoutCallback();
},
expiresMsecs),
totalDurationMsecs: expiresMsecs,
expirationDate: new Date(Date.now() += expiresMsecs)
};
},
updateTimer: function () {
if (document.timerData) {
//
// Calculate the msecs remaining so it can be used to set a new timer.
//
var timerMsecs = document.timerData.expirationDate - new Date();
//
// Kill the previous timer because a new one needs to be set or the callback
// needs to be fired.
//
this.cancelTimer();
if (timerMsecs > 0) {
this.setTimer(timerMsecs);
} else {
timeoutCallback();
}
}
},
cancelTimer: function () {
if (document.timerData && document.timerData.timerId) {
clearTimeout(document.timerData.timerId);
document.timerData = null;
}
}
};
};
You could have the manager function take a millisecond parameter instead of passing it into set, but again this is modeled somewhat after the angular service I wrote. The operations should be clear and concise enough to do something with them and add them to your own app.
var timeoutCallback = function () { console.log('timer fired!'); };
var manager = timeoutManager();
manager.setTimer(20000);
You will want to update the timer once you get the resume event in your event listener, like so:
// do something when the app awakens
document.addEventListener('resume', function () {
var manager = timeoutManager();
manager.updateTimer();
}, false);
The timeout manager also has cancelTimer() which can be used to kill the timer at any time.
You can use this class github.com/mustafah/background-timer based on #jlafay answer , where you can use as follow:
coffeescript
timer = new BackgroundTimer 10 * 1000, ->
# This callback will be called after 10 seconds
console.log 'finished'
timer.enableTicking 1000, (remaining) ->
# This callback will get called every second (1000 millisecond) till the timer ends
console.log remaining
timer.start()
javascript
timer = new BackgroundTimer(10 * 1000, function() {
// This callback will be called after 10 seconds
console.log("finished");
});
timer.enableTicking(1000, function(remaining) {
// This callback will get called every second (1000 millisecond) till the timer ends
console.log(remaining);
});
timer.start();
Hope it helps, Thank you ...
You should use the Page Visibility API (MDN) which is supported just about everywhere. It can detect if a page or tab has become visible again and you can then resume your timeouts or carry out some actions.

jQuery / backbone.js - delay function call

I have a #search element, which when the keyup event occurs should fire a function. This function should only fire if keyup hasn't occurred in a set amount of time (say 500 milliseconds for example). This will prevent search results from updating every letter that is pressed. The problem is that with backbone.js, I have my events in a hash and the one that is applicable looks like:
'keyup #search' : 'setSearch'
which calls the setSearch() function when the keyup event occurs. I'm not really clear on how to handle it at this point. I've tried a variety of things, but nothing can maintain the timer past the function ending.
I have something like so:
setSearch: function(event) {
var timer = window.setTimeout( function() {
// run function here
alert('fired');
}, 500);
},
rather than the alert('fired'), I'll have my own function run. I can see why this code doesn't work (a timer is set for every keyup event that occurs. But I still don't have a clear idea on what else I could try.
What you are looking for is actually a function provided to you from underscore.js (a requirement of Backbone)
setSearch: _.throttle(function() {
//Do Stuff
}, 500),
In a nutshell, this returns a new form of the anonymous function that can only be called once every 500ms. You will likely have to tweak the timing to your needs.
More Info:
http://documentcloud.github.com/underscore/#throttle
You need an instance variable in your view that stores the timer ID, then you can stop it and restart it as needed:
setSearch: function(event) {
var self = this;
if(self.timer)
clearTimeout(self.timer);
self.timer = setTimeout(function() {
alert('fired');
self.timer = null;
}, 500);
}
So, if the timer is already running, you call clearTimeout to stop it, start a new timer, and store the timer ID in self.timer (AKA this.timer). You'll also want to reset the stored timer ID in the timer's callback function or your setSearch won't do anything after its timer has fired once. And all the self business is just to capture this for use in the timer's callback function.
Preventing the updating of search results on every keyup is exactly the kind of situation that Underscore's _.debounce(function, wait) function is meant to deal with. The underscore documentation for _.debounce() states:
Creates and returns a new debounced version of the passed function which will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked. Useful for implementing behavior that should only happen after the input has stopped arriving.
Your refactored code would look as simple as:
setSearch: function(event) {
_.debounce(doSomething, 300);
},
Since you want your event handler events to be able to maintain whether or not an event has recentlyFired, you probably want to wrap your handler into a closure and maintain that status. The status should be changed to true when an event has fired, and reset to false after a delay of 500ms.
setSearch: function( ) {
var firedRecently = false;
return function(event) {
if (firedRecently) {
// it has fired recently. Do you want to do something here?
} else {
// not fired recently
firedRecently = true;
// run your function here
alert('fired');
var resetStatus = window.setTimeout( function () {
firedRecently = false;
}, 500);
}
}
}( );

Javascript: Do processing when user has stopped typing

I have a text box on a web page, whose value I want to send to a XMLHttpRequest. Now I want the user to just type the value, without pressing a button. But If i just send the request int he keyboard events, it will fire every time a key is pressed.
So basically I want something liek this
function KeyUpEvent()
{
if (user is still typing)
return;
else
//do processing
}
It would be great if the solution could come from plain javascript or mootools. I dont want to use any other library.
The way this is usually done is by restarting a timer on the keyup event. Something like this:
var keyupTimer;
function keyUpEvent(){
clearTimeout(keyupTimer);
keyupTimer = setTimeout(sendInput,1000); // will activate when the user has stopped typing for 1 second
}
function sendInput(){
alert("Do AJAX request");
}
Basically, you want to start a timer on KeyUp, and when KeyUp starts again, reset the timer. When the user stops typing, the timer runs out, and your request can go at that point.
Example:
var timout_id;
function keyup_handler(event) {
if (timout_id) {
clearTimeout(timout_id);
}
timout_id = setTimeout(function(){
alert('sending data: \n' + event.target.value)
}, 800);
}
Just attach the function to the input using your preferred method, and replace the alert with your preferred action.
Of course there are many ways you could generalize this approach and make it more reusable, etc, but I think this illustrates the basic idea.
I always use this simple function to handle a timer, that will fire a callback function, after the user has stopped typing for a specified amount of time:
var typewatch = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
}
})();
Usage (example with MooTools):
$('textInput').addEvent('keyup', function(e){
typewatch(function () {
// executed only 500 ms after the last keyup event
// make Ajax request
}, 500);
});
The main difference between this solution and solutions from other answers is that all the timer logic is handled by the typewatch function itself, the event handler doesn't need to know anything about the timer, it just invokes the function. Also, there are no global variables to take care (the timer id is not stored on a global variable).
You never know when a user is really "finished" typing. The user might take a sneeze break, or a stretch break, or a coffee break, and then continue typing.
However, if you're implementing something like an autocomplete mechanism, you can set a timer (cf. window.setTimeout(...)) to see if the user hasn't typed anything in a certain amount of time. If you get another key-up event while the timer is running, you can start the timer over.
var keyTimer;
function onKeyUp(){
clearTimeout(keyTimer);
setTimeout(stoppedTyping,1500);
}
function stoppedTyping(){
// Profit! $$$
}
EDIT: Damn ninjas
I wrote a custom jQuery event because I use this logic a lot:
jQuery.event.special.stoppedtyping = {
setup: function(data, namespaces) {
jQuery(this).bind('keyup', jQuery.event.special.stoppedtyping.keyuphandler);
},
teardown: function(namespaces) {
jQuery(this).bind('keyup', jQuery.event.special.stoppedtyping.keyuphandler);
},
keyuphandler: function(e) {
var interval = 1000;
var el = this;
if (jQuery.data(this, 'checklastkeypress') != null) {
clearTimeout(jQuery.data(this, 'checklastkeypress'));
}
var id = setTimeout(function() {
jQuery(el).trigger('stoppedtyping');
}, interval);
jQuery.data(this, 'checklastkeypress', id);
}
};
You can use it like this:
$('input.title').bind('stoppedtyping', function() {
// run some ajax save operation
});
For some reason I could never get it to work with .live( ... ). I'm not sure why...
Use onBlur and maybe an onKeyDown to check for the user pressing the return/enter key.

Javascript - Which event to use for multiselect change

I'm using YUI as javascript framework, and can successfully react when the user changes the value of basic input fields, the reaction being to sent an Ajax query.
However, I'm not so lucky with multiselect dropdown lists:
listening to "change" would send my query each time the user adds/removes an item to his selection
listening to "blur" requires the user to click elsewhere in order to loose the focus and send the query (not very usable), plus it would send the query if the user only scrolls on the list without changing anything (useless, confusing).
Any idea (with YUI), that would use a clever behavior?
Or should I really listen to change and implement a timeout (to wait for subsequent changes before sending a query)?
I use the same kind of timeout you want on key events, to detect when the user have finished typing, the same approach can be used on your problem:
// helper function
var timeout = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
Usage:
// YUI 2
YAHOO.util.Event.addListener(oElement, "change", function () {
timeout(function () {
// one second since the last selection change
}, 1000);
});
// YUI 3
Y.on("click", function () {
timeout(function () {
// one second since the last selection change
}, 1000);
}, oElement);
Basically in this timeout function, I reset the timer if the function is called before the specified delay.
you could run a setTimeout after the onChange event and keep track of a number of changes to determine whether or not a change had been made since the event was fired. if no changes were made within that time, then the query could be sent.
e.g., something like:
var changes = 0;
function myOnChangeHandler(e)
{
changes++;
var local_change = changes;
setTimeout(function() {
if (local_change === changes) {
sendRequest();
}
}, 500);
}

Categories