Is there any DOM event for when the browser tab loses/gains focus? I know there are the blur and focus events on window, but they also fire when the browser window as a whole loses focus. The browser might then be still visible to the user. Of course such an event would be browser specific, but that's ok.
The reason why I want this is because I run animations that might consume quite some CPU time. When the browser tab is not visible there is no reason to continue animating. Now I know that modern browsers reduce the timer resolution of background tabs, but I could actually pause the animation, so that no CPU time whatsoever is consumed.
In case you are wondering, this is what I'm writing:
http://panzi.github.com/Browser-Ponies/
At least Google Chrome supports a webkitvisibilitychange event and a document.webkitHidden property. See the visibility API. But it seems only to fire when the shown tab changes, not when the whole window is minimized. There also seems to be a visibilitychange event for Internet Explorer, but the documentation doesn't say anything about it.
The closest thing I believe you'll find is the top answer here:
Is there a way track the focus on tab with Javascript?
Now they have exactly what was needed:
https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API
Related
OK, I'm trying to reset the activeElement from the middle of the page so that the tab key would start from the top like, the same way as the page is just refreshed.
For that purpose (tested in FF and Chrome) I'm trying to use document.activeElement.blur() (from the browser console). As result, the selection of the <a href></a> gets visually removed (nice).
Also,running
document.activeElement after running document.activeElement.blur()
from console shows
<body class="ng-tns-0-0">
which looks good (the activeElement is body now?)
However, if I close the console and hit the Tab key, the focus appears on the next to the previous a href - Not to the link that is focused on page load + Tab key.
Why and how to fix that behavior?
The question appeared from the accessibility point of view, as the significant part of the page gets rendered with another content. The tab key needed to start over, like for a new page.
In fact, you shouldn't use blur() ever, and this method shouldn't even exist.
After having called blur(), you have no control of where the focus goes. It may go in menu bar, toolbars, or even go totally outside of the browser and/or become completely unrecoverable without a mouse.
The behavior you observe with firefox and chrome isn't standard, isn't specified anywhere, may depend on OS and/or browser settings, and you don't have control at all on it
The safest solution if you want to go back to the first element of the page is probably to focus that first element, rather than calling blur() and hope for the best.
In order for any application or website to be keyboard accessible, the focus must always be under control, i.e. you must always know exactly where it is. As the method blur() doesn't specify where the focus goes next, you lose control of the focus when using it; so you should never use it. As far as I know, it has probably no legitimate use.
For whatever reason, natively in Chrome, mousemove events that immediately follow a mousedown event are not firing or are simply ignored altogether for a small period of time (500-1000ms?) following the mousedown event.
Strange thing is that this issue is nonexistent on codepen (on Chrome too) and the code is the exact same... There's also no issues with Firefox, Edge, etc, only natively on Chrome.
Here is a codepen nonetheless. Test it for yourself.
Copy and paste this code into actual .html, .css, and .js files, and then run it in the browser directly, you'll notice that paper.onmousemove does not fire or register immediately after a window.resize event for a very small period of time.
None of this makes any sense!
Anybody have any idea what's going on? Why would it work fine in codepen (and every other browser), yet not directly in the browser?!
I have found one issue with the codepen version, which produces a very similar bug (but involves a couple extra steps in the beginning).
Create an element by dragging your mouse on the white area
Select that element by clicking it
Drag that element anywhere on the page
Resize the browser and immediately try to create another element by dragging
However, on codepen mousedown isn't firing in this case, whereas mousemove is not firing if viewed directly in the browser. Again, there is a discrepancy, which incredibly bizarre.
Update
It turns out it only happens when the developer console is open, which is why it was not happening in codepen.
This seems to be some weirdness with Chrome DevTools. The bug you describe seems to only occur when DevTools is open. It goes away when you close DevTools. It may just be a weird coincidence, but it starts logging out mousemove events immediately when the resolution label in the top right goes away.
That being said, you have a combination of onmousemove and addEventListener going on. For instance you have both
paper.addEventListener('mouseup', checkMouseUp)
and
paper.onmouseup = function(event) {}
I'm not sure if it's the cause of the DevTools issue, but this can lead to unintended consequences since paper now has two separately assigned mouseup functions. In your case, I'd just stick with addEventListener.
I have the following code, it fades elements in and out in a repeating cycle. When the tab is inactive the text within the divs piles up on top of each other for a split second before being cleared when the tab is activated again. Is there a way to stop this animation when the window blurs and start it again on focus?
(cycle = function () {
setTimeout(function(){$('#right').fadeOut(1000)},10000);
setTimeout(function(){$('right').fadeIn(1000)}, 11000);
setTimeout(function(){$('#left').fadeOut(1000)},13000);
setTimeout(function(){$('#left').fadeIn(1000)},14000);
setTimeout(function(){$('#left').fadeOut(1000)},15000);
setTimeout(function(){$('#left').fadeIn(1000)},17000);
})();
I gave a suggestion in a comment, but then remembered that that solution is not necessarily cross-browser compatible, as I had come across it before, thus the creation of my plugin.
Suffice it to say, $(window).blur() and focus do not always work as expected on all browsers. I don't remember the exact list of problems I ran into, but I know some were things like; clicking on another tab (in FF, i think) did not trigger the blur, clicking on another program would trigger the blur despite the fact my main browser window was still open and that tab had focus, it ddnt have Windows Focus, etc...
The following plugin I created might be helpful in that I've filed it down to work in "most" browsers and versions (not tested on all versions) and it functions exactly as we expect where I work. It only goes blur if the exact browser window's tab loses focus to another tab of the same browser. And of course vice versa with focus.
See jsFiddle Example usage and unminified code
Minified Plugin:
Simply Add to a js file to be called after jquery or place at top of your code
(function(jQuery){jQuery.winFocus||(jQuery.extend({winFocus:function(b){function c(a){a=a||window.event;a.hidden=a.type in{focus:"visible",focusin:"visible",pageshow:"visible",blur:"hidden",focusout:"hidden",pagehide:"hidden"}?"focusout"===a.type:this[d];jQuery(window).data("visible",!a.hidden);jQuery.winFocus.methods.exeCB(a)}var d="hidden";d in document?document.addEventListener("visibilitychange",c):(d="mozHidden")in document?document.addEventListener("mozvisibilitychange",c):(d="webkitHidden")in document?
document.addEventListener("webkitvisibilitychange",c):(d="msHidden")in document?document.addEventListener("msvisibilitychange",c):"onfocusin"in document?document.onfocusin=document.onfocusout=c:window.onpageshow=window.onpagehide=window.onfocus=window.onblur=c;for(x in arguments)"object"==typeof arguments[x]?(arguments[x].blur&&(jQuery.winFocus.methods.blur=arguments[x].blur),arguments[x].focus&&(jQuery.winFocus.methods.focus=arguments[x].focus),arguments[x].blurFocus&&(jQuery.winFocus.methods.blurFocus=
arguments[x].focus)):"function"==typeof arguments[x]&&(void 0===jQuery.winFocus.methods.blurFocus?jQuery.winFocus.methods.blurFocus=arguments[x]:(jQuery.winFocus.methods.blur=jQuery.winFocus.methods.blurFocus,jQuery.winFocus.methods.blurFocus=void 0,jQuery.winFocus.methods.focus=arguments[x]))}}),jQuery.winFocus.methods={blurFocus:void 0,blur:void 0,focus:void 0,exeCB:function(b){jQuery.winFocus.methods.blurFocus?jQuery.winFocus.methods.blurFocus(b,!b.hidden):b.hidden?jQuery.winFocus.methods.blur&&
jQuery.winFocus.methods.blur(b):jQuery.winFocus.methods.focus&&jQuery.winFocus.methods.focus(b)}})})(jQuery);
Also: #line-o 's referenced SO Question is where I was first inspired to write this plugin and I also have this plugin answer posted there. lol
Take a look at the Visibility API for current browser. You'll still need a fallback for older ones (namely IEs).
Or you might find a solution here:
Is there a way to detect if a browser window is not currently active?
I'm currently toying around with some autocomplete form fields, and am finding it very hard to inspect the generated drop down items. As soon as I click on the "inspect element" button or try to right click on the dropdowns, the original autocomplete input runs an onclick event (or something that triggers on a focus change) and hides, deletes or otherwise modifies the element I was trying to inspect.
Is there a way to work with the debugger so that the mouseclicks and other commands I give to it don't get intercepted by the script I'm trying to debug?
I currently have this kind of problem on both Firebug and on Chrome's inspector. The only solution I can think right now would be setting some smart breakpoints inside the appropriate event handlers but that is hard to do if I don't know what event handlers to look for or where they are hidden in the original code...
You could set a breakpoint and inspect after it is triggered, I have noticed that freezes the DOM.
You need to use breakpoints. As far as tracking down what's happening where, Chrome's "Call Stack" window can be very helpful.
Cheers
In Firebug you have a Break on next item in Script panel. Since Firebug 1.10, there's a keyboard shortcut for this: Ctrl+Alt+B on Windows (it works even if focus is in the page, not in Firebug).
You'll probably need to have Script panel focused in Firebug since this is a shared shortcut for Break on... which differs in each panel.
It generally freezes the DOM although it's not 100% reliable.
It's also not ideal because it will stop at any JavaScript execution, and will not be helpful if there is some aggressive polling in the background, or global capturing of keyboard events. Anyway it's still better than nothing.
Chrome pauses Javascript execution on F8; it took a bit of repetition but pressing F8 at the right time prevented JS from defocusing the element.
If you are having problem selecting the element, you can try cmd + shift + c on Mac to select the element without right clicking it.
If its DOM manipulation problem, you might try to force state on the input element by right clicking on the element in the Elements panel and set force state to focus.
Open the docked DevTools first (the undocked approach will not work due to the OS limitations.)
Once the autocomplete box is displayed, right-click it and select "Inspect Element" in the context menu. The focus will move to the DevTools but the autocomplete box will still be shown (this worked for me on Linux, tip-of-tree Chromium, M25. Your mileage may vary.)
/**
* Utility to freeze actual DOM state, for example dropdown menu
*/
function easyBreak() {
function doBreak() {
// put breakpoint here to freeze actual dom and write to console easyBreak()
// you have 3 seconds to get to desired state
var a = 0;
}
window.setTimeout(doBreak, 3000);
}
You could use DOM breakpoints.
I'm having a similar case here : I want to inspect dropdown items that only show when the input has focus.
On Chrome, I right-click on the parent element and choose Break on > Subtree modifications.
It will pause - like it does with JS breakpoints - anytime the DOM changes within that parent. You can then inspect the children while the DOM is frozen.
Currently I am developing a web application for which I am using a pre-loader icon. What I want is that the pre-loader becomes visible every time the user navigates to another page or refreshes the page. So far I have the following solution:
window.onbeforeunload = function() { $("applicationdisabler").show(); };
For Safari and Firefox it works fine when the user clicks a link or refreshes the page. However in IE7 the div only becomes visible when the user clicks a link and NOT when the user refreshes the page.
The user can refresh the page by hitting F5 (on Windows) or any other possible way the browser provided.
Of course I have been looking for some workarounds already. The following code shows the alert in IE7, but the div still doesn't become visible.
window.onbeforeunload = function() { $("applicationdisabler").show(); alert("come on!"); };
The code of my div:
<div id="applicationdisabler"><img src="images/preloader.gif" /></div>
Hopefully someone can help me out.
You need to put the # before the id on the jQuery selector:
$("#applicationdisabler").show();
Why not use just use the onLoad listener instead? Although it would be slightly slower it should be more reliable.
Actually after a bit of looking around I'm not sure modifying the DOM makes any sense unless the onBeforeUnload handler returns false first - i.e. forces the user to stay on the same page.
As I understand it the onBeforeUnload event is fired just before the page is unloaded, so if you don't return false the browser will unload the page and DOM, and any JavaScript executed after that will be pointless.
That doesn't quite explain why JavaScript isn't executed properly in the onBeforeUnload function, but from what I've seen sites only use the window.alert or window.prompt dialogs to ask the user if they want to leave the site, and then often executing JavaScript if the user decides to stay.
Hence I'm guessing that some browsers may not allow DOM manipulation when this event is fired - since if the page is unloaded any DOM manipulation done is completely pointless.
So either:
Return false in your onBeforeUnload method, and then show your preloader (although this will stop navigation to the next page)
Use the onLoad event of the next page to show the preloader image instead
Also note: Opera versions 9.5 and below do not support this event (I'm unsure about later versions) but GMail does manage to catch the back button in Opera.
Possibly related is this security warning for IE7's implementation of the onBeforeUnload event - it's possible Microsoft patched it in a way that prevents the things you're trying to do. And I know IE6 and below don't allow commands like document.location='' in the onBeforeUnload handler for security reasons.