Google Chrome: how to fetch "minimized" event? - javascript

I try to fetch all events when the state of a window changes. So far, I use a content script that adds a "resize" listener to the window: window.onresize = function() {...}. This allows me to fetch when a window's state changes to "normal", "maximized" and "fullscreen".
However, I have no idea what to do to also get "minimized". Minimizing a window does not fire "resize" events. I tried to use the onFocusChanged API to add an listener, i.e., chrome.windows.onFocusChanged.addListener(function(windowId) {...}));, but it has its issues. Firstly, if the window I minimize has the focus, windowId = -1 (chrome.windows.WINDOW_ID_NONE), so I cannot fetch the window to readout its state. And secondly, if the window doesn't have the focus, the onFocusChanged event is not fired.
In short, how can I detect when a Chrome window has been minimized?

I think this might help:
chrome.windows.onFocusChanged.addListener(function() {
console.log("Focus changed.");
chrome.windows.getCurrent(function(window){
console.log(window.state);
if(window.state == "normal") {
console.log("It's normal.Stop the watch.");
} else if(window.state == "maximized"){
console.log("It's maximized.Start the watch.");
} else if(window.state == "minimized"){
console.log("It's minimized.Start the watch.");
}
});
});

Related

Trigger event when user clicks the browsers back button

Is it possible with jquery to trigger a function when the user clicks the browsers back button.
I have a lightbox/widget that when open fills the window when it is open. There is a close button etc but this would be good if this closed if a user hit the back button by mistake.
I have this so far but the function doesnt seem to run at all
$(window).on("navigate", function (event, data) {
event.preventDefault();
console.log('BACK PRESSED');
var direction = data.state.direction;
if (direction === 'back') {
if(widgets.full_active){
$('.close', widgets.active_widget).click();
event.preventDefault();
console.log('CLOSE THIS');
}
}
if (direction === 'forward') {
// do something else
}
});
By not running this line at the start of the function event.preventDefault(); should mean the page never changes
Usually, I do this using the native JavaScript API from the browser, like described here: Manipulating the Broser History.
With jQuery, I see people usually using this plugin: History.js, although I have no idea what is it's status.
The event you're looking for is onpopstate.
A popstate event is dispatched to the window every time the active
history entry changes between two history entries for the same
document.

Identifying window focus/blur events with iframes

I'm trying to reliably identify when a browser window/tab is activated and deactivated. Normally, window's focus and blur events would do, but the document contains several iframes.
When an iframe is focused, the main window gets unfocused and vice versa, so we have the following possibilities of focus events [(none) means the window/tab is deactivated]:
current focus new focus events
----------------------------------------------------------------------
window (none) window:blur
window iframe window:blur + iframe:focus
iframe (none) iframe:blur
iframe window iframe:blur + window:focus
iframe another iframe iframe:blur + iframe:focus
(none) window window:focus
(none) iframe iframe:focus
It is no problem to register all of these events, as shown by this fiddle. But whenever we switch from the main window to an iframe or vice versa, or between two iframes, the respective blur and focus events both fire; and they fire with a small delay at that.
I am worried about the concurrency here, since the blur handler could go and start doing stuff, but it should have never started because the user actually just switched focus somewhere in between the frames.
Example: A page should do some AJAX requests periodically whenever it is currently not active. That is, it should start requesting whenever the user deactivates the tab and stop requesting as soon as it's activated again. So we bind a function to the blur event that initiates the requests. If the user just clicks on another iframe, blur, and shortly after that, focus is triggered. But the blur handler already fires away, making at least one request before it can be stopped again.
And that's my problem: How can I reliably detect when a user actually (de-)activates a browser window containing iframes, without risking to get a false alarm caused by two immediate blur and focus events?
I wrote a half-baked solution that uses a timeout after a blur event in order to determine if there was an immediate focus event after it (fiddle):
var active = false,
timeout = 50, // ms
lastBlur = 0,
lastFocus = 0;
function handleBlur() {
if (lastBlur - lastFocus > timeout) {
active = false;
}
}
function handleFocus() {
if (lastFocus - lastBlur > timeout) {
active = true;
}
}
$(window).on('focus', function () {
lastFocus = Date.now();
handleFocus();
}).on('blur', function () {
lastBlur = Date.now();
window.setTimeout(handleBlur, timeout);
});
$('iframe').each(function () {
$(this.contentWindow).on('focus', function () {
lastFocus = Date.now();
handleFocus();
}).on('blur', function () {
lastBlur = Date.now();
window.setTimeout(handleBlur, timeout);
});
});
But I believe this could be very problematic, especially on slower machines. Increasing the timeout is also not acceptable to me, 50 ms is really my pain threshold.
Is there a way that doesn't depend on the client to be fast enough?
you could poll for the document.hasFocus() value, which should be true if either an iframe or the main window are focused
setInterval(function checkFocus(){
if( checkFocus.prev == document.hasFocus() ) return;
if(document.hasFocus()) onFocus();
else onBlur();
checkFocus.prev = document.hasFocus();
},100);
function onFocus(){ console.log('browser window activated') }
function onBlur(){ console.log('browser window deactivated') }
I was trying to do it without polling, but the iframe doesn't fire an onblur event (if the browser window is deactivated when the iframe was on focus, I get no events fired), so I ended up needing polling for half of it anyway, but maybe someone can figure something out with this code
function onFocus(){ console.log('browser window activated'); }
function onBlur(){ console.log('browser window deactivated'); }
var inter;
var iframeFocused;
window.focus(); // I needed this for events to fire afterwards initially
addEventListener('focus', function(e){
console.log('global window focused');
if(iframeFocused){
console.log('iframe lost focus');
iframeFocused = false;
clearInterval(inter);
}
else onFocus();
});
addEventListener('blur', function(e){
console.log('global window lost focus');
if(document.hasFocus()){
console.log('iframe focused');
iframeFocused = true;
inter = setInterval(()=>{
if(!document.hasFocus()){
console.log('iframe lost focus');
iframeFocused = false;
onBlur();
clearInterval(inter);
}
},100);
}
else onBlur();
});

Detecting a button that is loaded asynchronously

On a web page I am looking at, there is a lot of data being loaded asynchronously.
Included with that data is a button called "View More". If you either click on the button or simply scroll right to the bottom, more data will be loaded via a "GET" call function.
When I try using this (in FireBug console):
document.getElementById('#button9').click();
or
document.getElementById('button9').click();
I get this result:
TypeError: document.getElementById(...) is null
document.getElementById('#button9').click();
From what I have read about this TypeError, the Id cannot be detected, which I assume is because of the data being asynchronous. Is there a way to detect the element (it doesn't show up on the "page source" but it is there when I click on "Inspect Element with FireBug")?
I would like to detect the element and then make a call to a click event to 'simulate a click' (meaning I would like a click to take place without clicking on the button or scrolling right down) with the output being displayed in the browser (per usual).
If you just want to attach the event, then the bottom will work.
If the problem is that it is null, and you don't know when it will show up, your best bet is to create a loop that runs until it exists.
var obj = document.getElementById('button9');
obj.addEventListener('click', function() {
alert(' you clicked on ' + this);
}, false);
in case its that second instance, and you want to wait until the object events, then use:
checkExists();
function checkExists() {
var obj = document.getElementById('button9');
if (obj != null) {
obj.addEventListener('click', function() {
alert(' you clicked on ' + this);
}, false);
alert('added event');
}
else {
setTimeout(checkExists, 1000);
}
}
This will work, no matter even if you don't know when the object is getting created and added to the DOM
//chrome / ff /IE
$("#button9").bind("DOMSubtreeModified", function() {
// Add click function here
});
//IE 8 and lower
$("#button9").bind("propertychange", function() {
//Add click function here
});
2nd Option
*OR*
Not sure if it supposts IE8 though but it definitely supports all others
document.addEventListener("DOMSubtreeModified", function (e) {
if ($(e.target.id) == "#button9") {
// Do stuff
}
}, false)
Explanation: It checks if the DOM has found an element with the specific ID, if so, execute the click function.

Closing a pop up window when it loses focus

I am wondering if it is possible to create a pop up window with javascript, and then close that window when it loses focus.
Here is my code:
var theWindow;
function launchWindow() {
theWindow=window.open('www.domain.com');
theWindow.onblur = function() {
this.close();
};
}
But that doesn't work at all. Any suggestions?
EDIT: I have discovered a solution that works for me, hopefully it will work for someone else:
var theWindow;
var windows = [];
function launchWindow() {
theWindow=window.open('www.domain.com');
windows.push(theWindow);
window.onfocus = function() {
for (x in windows) {
windows[x].close();
}
};
}
It's not an exact solution to my original problem (It doesn't close the window when it loses focus, but rather it closes it when the main window regains focus) but it works for me.
Is the URL of the popup window from the same domain as the parent? If not, you will likely not be able to attach an event to the new window's onblur event.
Run this from your browser console while viewing StackOverflow to see that it does in fact work when the popup is on the same domain as the originating window:
var theWindow = window.open ("http://www.stackoverflow.com","theWindow");
theWindow.onblur = function() { this.close(); };
window does not have the onblur event
Try to call it's closing by focusing on the <body> of the main window
The problem you may be having is that you are binding the onblur handler before the window has begun loading the page. Once the page is loaded, your onblur handler is gone. You'll need to defer binding long enough to give the page a chance to start loading before binding your event handler:
function launchWindow() {
var theWindow = window.open('www.domain.com');
setTimeout(function() {
theWindow.onblur = function() {
this.close();
};
}, 2000);
}
If you are loading a page in a different domain, you won't be able to bind the onblur handler at all. You'll need to stick to your solution using onfocus.

Capturing result of window.onbeforeunload confirmation dialog

Is there a way to capture to result of the window.onbeforeunload confirmation dialog like the one below from Stack Overflow (this happens when leaving the 'Ask Question' page without posting the question)?
This is how it appears in Chrome, I believe it's slightly different in other browsers, but you always have some form of yes/no buttons.
Presumably if they're still on the offending page after the event has been triggered they chose to stay and you could probably figure this out by watching the sequence of js. However I would like to know how to determine if they clicked "Leave this page"?
I've implemented this like below:
// concept taken from SO implementation
function setConfirmUnload(showMessage, message) {
window.onbeforeunload = showMessage ? (message ? message : "this is a default message") : null;
}
// pseudo code
listen to changes on inputs
if any inputs fire a change event
call setConfirmUnload(true, 'My warning message')
note I'm using jQuery within my site.
I'm essentially trying to implement a Gmail like drafting implementation, wherein if a user leaves a page with a form they've made changes to without saving they're warmed with a similar dialog. If they choose to discard they're changes and leave the page, I need to clean up some temporary records from the database (I'm thinking an AJAX call, or simply submitting the form with a delete flag) then sending them on their way.
My question also relates to:
jQuery AJAX call in onunload handler firing AFTER getting the page on a manual refresh. How do I guarantee onunload happens first?
You can have the exit confirmation using window.onbeforeunload but there isn't a way to find out which button the user clicked on.
To quote an earlier response from jvenema from this thread:
The primary purpose for the
beforeunload is for things like
allowing the users the option to save
changes before their changes are lost.
Besides, if your users are leaving,
it's already too late [...]
How about this:
$( window ).bind( 'beforeunload' , function( event ) {
setTimeout( function() {
alert( 'Hi againe!' );
} );
return '';
} ).bind( 'unload', function( event ) {
alert( 'Goodby!' );
} );
Late to the party, but I found the following code (in TypeScript) to be a decent way to detect if the person clicked on 'Ok' on that confirmation dialogue window.
public listenToUnloadEvents(): void {
window.addEventListener('beforeunload', (e) => {
const confirmationMessage = '\o/';
(e || window.event).returnValue = confirmationMessage; // Gecko + IE
return confirmationMessage; // Webkit, Safari, Chrome etc.
});
window.addEventListener('unload', () => {
this.sendNotification(Action.LEFT)
});
}
I'm not sure how much time you have to run code in the unload event, but in this instance, I am sending a notification through Socket.io, so it's very quick at completing.
As for detecting the cancel on that notification, as someone else mentioned, creating a global variable like let didEnterBeforeUnload = false could be set to true when the beforeunload event fires. After this, by creating the third event, like so (again, in TypeScript), you can infer the user pressing cancel
window.addEventListener('focus', (e) => {
if (didEnterBeforeUnload) {
console.log('pressed cancel')
}
didEnterBeforeUnload = false
});
As a side-note though, these events won't (iirc) fire unless you have interacted with the page. So make sure to click or tap into the page before trying to navigate away during your testing.
I hope this helps anyone else out there!

Categories

Resources