recursive setTimeout() pause on background - javascript

I have a piece of code:
var logo = $("#blinking-logo");
function logo_blink() {
logo.fadeOut(10).delay(10)
.fadeIn(10).delay(20)
.fadeOut(10).delay(10)
.fadeIn(10)
window.setTimeout(logo_blink, (Math.random()*(1500))+1500);
}
logo_blink();
All it makes is blinking a picture once in ~30 seconds (time is less here for easier debugging)
The problem that Chrome pauses this timer while the tab in backgrounded, and then, when coming back to that tab, it blinks all the blinks that were missed in background.
I'd like to pause the timer while in background, but I don't know how. I've read some related posts, but it seems that they describe the opposite problem. Is there any way to detect the backgrounding of a tab?

It is a known feature. To conserve the resources Chrome does not update the window without focus :) You could check, for example, that window lost its focus and stop the timer. Start it again when window is in focus. For example:
var timer = null;
var logo = $("#blinking-logo");
function logo_blink() {
if(timer) clearTimeout('timer');
logo.fadeOut(10).delay(10)
.fadeIn(10).delay(20)
.fadeOut(10).delay(10)
.fadeIn(10)
timer = window.setTimeout(logo_blink, (Math.random()*(1500))+1500);
}
logo_blink();
$(window).blur(function(){clearTimeout(timer); timer = null;});
$(window).focus(function(){if (!timer) timer = window.setTimeout(logo_blink, (Math.random()*(1500))+1500);});
Something like this. On one of my pages with animation a had the same problem with setInterval, so I just pause it when the page is in background.
if (!$.browser.msie)
{
$(window).focus(function(){paused = false;});
$(window).blur(function(){paused = true;});
}
And than skipped animation based on the value of paused flag.
ps: Code is updated with optimization discussed below.

Chrome, Firefox and IE10 have page visibility APIs that you can use to determine when you page is no longer visible. This works better than using focus in some circumstances. Here's an example from MDN:
//startSimulation and pauseSimulation defined elsewhere
function handleVisibilityChange() {
if (document.hidden) {
pauseSimulation();
} else {
startSimulation();
}
}
document.addEventListener("visibilitychange", handleVisibilityChange, false);
And, some reference documents:
http://code.google.com/chrome/whitepapers/pagevisibility.html
https://developer.mozilla.org/en/DOM/Using_the_Page_Visibility_API
W3 Document: http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html
The only work-arounds I've seen for older browsers involve determining whether your window has focus or not which isn't perfect, but maybe better than nothing in some cases.

Related

removeEventListener("timeUpdate", myFunction) is unstable during video play

An event listener is added once my video starts playing. That is
document.getElementById("myVideo").addEventListener("timeUpdate", myFunction);
and then just before the video ends I want something to happen (perhaps a fade out) along with the last few seconds of the video (or to keep things simple I'm just going to write something like alert("goodbye");) instead.
and when I use this piece of code
var myVideo = document.getElementById ("myVideo");
function myFunction(){
if(myVideo.currentTime >= (myVideo.duration-3) )
{
alert("this goodbye message is supposed to be displayed only once and exactly three seconds before the video ends");
myVideo.removeEventListener("timeupdate", myFunction);
}
}
it works in Chrome but it's unstable. Sometimes it works fine but other times the alert keeps popping a few times before the event listener is actually removed (which is bad in my case). In Firefox it is even worse as it fires many times.
I know that different browsers make timeupdate event fire at very different intervals.
So what do you think? Should I give up on the
addEventListener()
removeEventListener()
couple and use
setInterval()clearInterval() to check where the playhead is and do stuff when the time comes.
That way instead of browser dependent time intervals I could set my own time interval for consistency. But does anybody know if there is a reliable way to do this with timeUpdate?
I used a timer instead and now it works perfectly.
var checkThePlayheadPositionTenTimesASecond = setInterval(myTimer, 100);
function myTimer()
{
if(myVideo.currentTime >= (myVideo.duration-3) )
{
alert("this video is going to end in three seconds");
clearInterval(checkThePlayheadPositionTenTimesASecond);
}
}
Still I'm going to leave this post active in case anyone has to say anything.

How to hide an element on click instead of timeout using Clippy.js?

I found a neat little JS library called Clippy.js that lets you implement Microsoft Word's old virtual assistants in your browser. After playing around with it for a while I realized that the text balloon has a setTimeout() method and a time delay causing it to disappear.
hide:function (fast) {
if (fast) {
this._balloon.hide();
return;
}
this._hiding = window.setTimeout($.proxy(this._finishHideBalloon, this), this.CLOSE_BALLOON_DELAY);
},
_finishHideBalloon:function () {
if (this._active) return;
this._balloon.hide();
this._hidden = true;
this._hiding = null;
},
I don't want that. I want the balloon to disappear when a user clicks. I tried registering an event listener by replacing this._hiding = ... with this:
var clickToHide = document.getElementsByClassName('clippy-balloon');
this._hiding = clickToHide.addEventListener('click', function(){$.proxy(this._finishHideBalloon, this)});
...but all that it does is hide the balloon completely. Why does that not work? And how do I achieve the functionality I want?
I think the delay is caused by the variable CLOSE_BALLOON_DELAY.
Changing this.CLOSE_BALLOON_DELAY to 0 should do the trick.

Refreshing browser on resize after certain amount

I have quite a complex page (responsive) with a lot of scripts running, and rather than trying to recalculate all these scripts when the browser is resized, I simply wish to trigger a refresh when the browser is resized.
Trouble is, that a refresh on browser resize sends Android devices, and some versions of IE into a refresh loop. I was thinking therefore to only refresh the browser after it has been resized a certain amount, and see if that cures the problem, which is what I'm attempting to do below. Though for some reason, the browser won't refresh at all. The counter works fine, but the window.location.reload(); doesn't appear to be working here (works outside of this function fine). Any ideas as to why this is?
var $resizeTolerance = 0;
jQuery(window).on("resize", function(){
$resizeTolerance++;
console.log($resizeTolerance);
if($resizeTolerance > 10) {
window.location.reload();
}
});
I would strongly recommend not doing this, not least because you've said you don't want to "...[try] to recalculate all these scripts when the browser is resized..." but of course that's exactly what you're doing: When the page is reloaded, you're repeating all the calcuations. Instead, make sure the calculations are repeatable, then repeat them.
But with that out of the way:
What you're looking for is setTimeout, to do something after the user is done resizing the browser:
var loadedAt = Date.now();
var resizeHandle = 0;
jQuery(window).on("resize", function(){
if (Date.now() - loadedAt < 300) {
// ignore
return;
}
if (resizeHandle) {
clearTimeout(resizeHandle);
}
resizeHandle = setTimeout(reloadPage, 100); // 100ms = 1/10th second
});
function reloadPage() {
window.location.reload();
}
That will wait until a tenth of a second after the last resize event occurs, and then trigger a page refresh. You may want to adjust the time.
It also ignores any resize event within 300ms of when the code hooks up the handler, to ignore the initial resize event the browser apparently sends.
Live Example
Side note: This uses Date.now, which nearly all browsers have at this point. You can shim it in older browsers like this:
if (!Date.now) {
Date.now = function() {
return +new Date();
}
}

Javascript pauses on iPad when changing tab: is there a way to know when coming back?

I've the same problem depicted in iOS 5 pauses JavaScript when tab is not active thread.
My question is if I can be noticed when come back to the paused tab.
onfocus and onblur events don't work on to the to be paused tab.
The code:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="http://code.jquery.com/jquery-1.7.1.min.js" ></script>
<script type="text/javascript">
window.onblur = function () {
console.log("blur");
$("#whatevent").append("blur<br/>");
}
window.onfocus = function () {
console.log("focus");
$("#whatevent").append("focus<br/>");
}
window.onunload = function () {
console.log("unload");
$("#whatevent").append("unload<br/>");
}
window.onload = function () {
console.log("load");
$("#whatevent").append("load<br/>");
}
</script>
</head>
<body>
<div id="whatevent"></div>
</body>
</html>
none but onload (but only the first time I load the page) events works on iPad when I switch tab.
Someone posed this very question over two years ago with this query. Unfortunately, it was met with only a couple of answers, one of which seems to be the only method to achieve this effect. Until Apple can implement the full Page Visibility API in mobile safari, I'm left with using this custom object I created that will use the API and fall back to a heart beat ticker if it's unavailable. However, as far as I can tell, there is no great way to check an imminent tab switch.
Here's a basic fiddle of the object demonstrating its only real method. It essentially just accepts a handler function for a focus event that gets fired whenever the browser returns the source tab. The fallback is hacky at best and will fire not just on a page re-entry but whenever scripting stops for longer than the timer threshold; which could be whenever the keyboard is visible, on scroll, or if a running script prevents the requestAnimationFrame from firing. Since scrolling is the most common behavior, I've added a handler that resets the last saved time so that the focus event refrains from firing.
This is the main portion of the script that includes the "hacky" method as described above:
_that.onFocus = function(handler, params) {
var hiddenProp = getHiddenProp();
console.log("Hidden prop: " + hiddenProp);
if (hiddenProp) {
var evtName = hiddenProp.replace(/[H|h]idden/, "") + "visibilitychange";
document.addEventListener(evtName, function(e) {
if (isHidden()) {
handler(e, params);
}
}, false);
}else {
var handlerObj = {"handler": handler};
if (params !== undefined) {handlerObj.params = params}
_handlers.push(handlerObj);
startLoop();
}
};
The rest may be read in the fiddle. In order to see the fallback you'll have to use a tablet (why else would you be needing this function without one?).
Note that the .onFocus method may accept an array of params for its second param that it will then pass to your event handler. This means that your event handler will always have an event object for it's first param (or null if the API is not supported) and your array of params as its second param.
Also not that this code has been tested for all of a couple hours so it may be prone to glitchiness. I would appreciate any constructive criticism to make it production worthy until Mobile Safari gets its butt in gear.

JWPlayer 4 javascript events are ignored

First of all, I can't upgrade to a newer version of the player, because I need the displayclick=fullscreen option to work, and it doesn't with version 5.
So, what I need to do is this: have the player auto-start with no volume and no controls on the page (this works just fine), and when the user clicks the screen the player must go full-screen and the volume must turn on.
The problem is all Javascript interaction seems to be completely ignored by the player, and I really can't see where the problem is.
When the page is loaded, I embed the player:
var so = new SWFObject('path_to_player.swf','div_id','200','120','10');
so.addParam('allowfullscreen','true');
so.addParam('allowscriptaccess','sameDomain');
so.addParam('bgcolor','#000000');
so.addParam('flashvars','file=path_to_playlist.xml&autostart=true&displayclick=fullscreen&controlbar=none&volume=0&icons=false&image=path_to_thumb.jpg');
so.write('div_id');
This seems to work just fine, the player is loading.
Then I add the event listeners:
var player = null;
function playerReady(p) {
player = document.getElementById(p.id);
addListeners();
}
function addListeners() {
if (player) {
console.log('add the listener');
console.log(player.getConfig().volume);
player.addControllerListener("RESIZE", "checkResize");
} else {
setTimeout("addListeners()", 100);
}
}
function checkResize(obj) {
console.log('resized');
if (obj.fullscreen) {
player.sendEvent("VOLUME", "60");
} else {
player.sendEvent("VOLUME", 0);
}
}
The "add the listener" message gets displayed in the console, but the second one, with the player's volume doesn't, and neither does the "resized" one when the player enters or exits fullscreen (and, obviously, the volume doesn't turn on).
I've tried other listeners, for both model and controller, and they don't seem to work. Sending events doesn't work either.
I've tried running just the code for the player separately, to make sure there are no other things interfering with the code, but I still have the same problem.
Well, it seems I've found the answer myself. Upgrading to a newer version of swfobject and using swfobject.embedSWF() seems to work just fine.

Categories

Resources