How to communicate with popup after reload - javascript

My page opens a popup and communicates with it using window.postMessage. To know when it is ready, one of the first things in the popup-script is:
window.opener.postMessage("initialize")
and then I reply and give the data and so on.
However if I have two instances of the same page open I'm running into a few problems. In Chrome and Firefox it actually opens individual popups even when the windowName is set. Setting focus using myPopup.focus() doesn't even seem to bring them up to the top. In IE however it reuses the same window, which I initially thought was a great improvement.
As stated in the spec, the window.opener reference is however never updated, even when another parent reopened it. Meaning the initial code will communicate with my first instance. I've tried in various ways to change the behavior, but I can't seem to communicate between these in any way.
Then I found a clever way of detecting this, storing the dimensions and position, then closing and reopening it. It looks like this:
const createPopup = (dimensions) => {
let features = "menubar=0,toolbar=0,status=0,personalbar=0,location=0,resizable=1,scrollbars=1";
const myPopup = window.open("/imageViewer.html", "ImageViewer", features);
if (myPopup.opener !== window) {
dimensions = { height: myPopup.outerHeight, width: myPopup.outerWidth, X: myPopup.screenX, Y: myPopup.screenY };
myPopup.close();
return createPopup(dimensions);
}
if (dimensions) {
myPopup.moveTo(dimensions.X, dimensions.Y);
myPopup.resizeTo(dimensions.width, dimensions.height);
} else {
myPopup.focus();
}
return myPopup;
};
The problem is that the main use I have for this is when the popup is located on a secondary monitor, and it doesn't seem to be allowed to neither move the popup outside the dimensions of the primary screen.
Is there anyway to solve this problem with using postMessage? My only other alternative which comes to mind is using localstorage to put information and look this up on intervals, but I'm not very happy with such a solution.
So to sum up I need to have a function (createPopup) which will create or bring a secondary window/popup to the front. The main window needs to be able to communicate with it, and it must work when using different instances of the same main page. (but running the function again when switching instances is OK.)

While setting in JavaScript failed, it works when setting directly when opening the window in the features-parameter:
export const createPopup = (dim) => {
let features = "menubar=0,toolbar=0,status=0,personalbar=0,location=0,resizable=1,scrollbars=1";
if (dim) {
features += ",left=" + dim.X + ",top=" + dim.Y + ",width=" + dim.width + ",height=" + dim.height;
}
const myPopup = window.open("/imageViewer.html", "ImageViewer", features);
try {
if (myPopup.opener !== window) {
throw Error("just trying to read opener will throw exception in IE if the opening window has been closed");
}
} catch {
dim = { height: myPopup.outerHeight, width: myPopup.outerWidth, X: myPopup.screenX, Y: myPopup.screenY };
myPopup.close();
return createPopup(dim);
}
myPopup.focus();
return myPopup;
};
Focus still doesn't seem to work in chrome-based browsers, but that is a very different bug indeed.

Related

Prevent child window from closing when parent window is closed in Electron

I'm making an Electron app. This app has a way to open a new window (popup) to be dragged on a different monitor. This window has a way to open another one, and so on. I need the user to be able to close a window he does not want, but keep others open.
First, I tried window.open but the child window gets closed when the parent is closed. I thought it must be because the var gets garbage collected.
Second, I tried binding to the new-window event in the main process.
This is what I did:
let windows = [];
function createNewWindow(){
let win = new BrowserWindow(
{
width: 1600,
height: 900,
webPreferences: {
nodeIntegration: true
}
}
);
win.webContents.on('new-window', (event, url) => {
event.preventDefault()
let win = createNewWindow();
win.loadURL(url);
event.newGuest = win;
})
windows.push(win);
return win;
}
But the child gets closed when the parent is closed. I checked the windows var, but it is correctly retained in the main process, so this should not be a GC problem.
How can I open a chain of windows (with or without window.open) without them being closed when the main parent is closed?
EDIT
As I did not found a way to keep windows open, I decided to hide the windows instead of closing them. This is what I did:
win.on("close", (event) => {
if (win.hideInsteadOfClose == true) {
event.preventDefault();
win.hide();
}
});
Where hideInsteadOfClose is a property I give to new windows created. This is not the proper way of doing it, but it gets the work done. Please feel free to answer with the correct way.
As I did not found a way to keep windows open, I decided to hide the windows instead of closing them. This is what I did:
win.on("close", (event) => {
if (win.hideInsteadOfClose == true) {
event.preventDefault();
win.hide();
}
});
Where hideInsteadOfClose is a property I give to new windows created. This is not the proper way of doing it, but it gets the work done.
Please feel free to answer with the correct way.

Detect if console/devtools is open in all browsers

I'm trying to create a script which will run when any browser console is opened or closed. Is there any way to detect if the browser console in all browsers (Firefox/IE/Chrome/Safari/Opera) is open or not via JavaScript, jQuery, or any other client-side script?
If you are willing to accept an interference for the user,
you could use the debugger statement, as it is available in all major browsers.
Side note: If the users of your app are interested in console usage, they're probably familiar with dev tools, and will not be surprised by it showing up.
In short, the statement is acting as a breakpoint, and will affect the UI only if the browser's development tools is on.
Here's an example test:
<body>
<p>Devtools is <span id='test'>off</span></p>
<script>
var minimalUserResponseInMiliseconds = 100;
var before = new Date().getTime();
debugger;
var after = new Date().getTime();
if (after - before > minimalUserResponseInMiliseconds) { // user had to resume the script manually via opened dev tools
document.getElementById('test').innerHTML = 'on';
}
</script>
</body>
devtools-detect should do the job. Try the simple demo page.
devtools-detect → detect whether DevTools is open, and its orientation.
Supported Browsers:
DevTools in Chrome, Safari, Firefox & Opera
Caveats:
Doesn't work if DevTools is undocked (separate window), and may show a false positive if you toggle any kind of sidebar.
I don't think it is directly possible in JS for security reasons.But in here
they are claiming that it is possible and is useful for when you want something special to happen when DevTools is open. Like pausing canvas, adding style debug info, etc.
But As #James Hill tell in this, I also thinks even if a browser chose to make this information accessible to the client, it would not be a standard implementation (supported across multiple browsers).
Also can also try this one also here.
It's not possible in any official cross browser way, but if the occasional false positive is acceptable, you can check for a window.onresize event. Users resizing their windows after loading a page is somewhat uncommon. It's even more effective if you expect users will be frequently opening the console, meaning less false positives as a percentage.
window.onresize = function(){
if ((window.outerHeight - window.innerHeight) > 100) {
// console was opened (or screen was resized)
}
}
Credit to https://stackoverflow.com/a/7809413/3774582. Although that question is chrome specific, the concept applies here.
To expand on this, if you need a very low tolerance on false positives, most window resizes will trigger this event dozens of times because it is usually done as a drag action, while opening the console will only trigger this once. If you can detect this, the approach will become even more accurate.
Note: This will fail to detect if the console is already open when the user visits the page, or if the user opens the console in a new window.
(function() {
'use strict';
const el = new Image();
let consoleIsOpen = false;
let consoleOpened = false;
Object.defineProperty(el, 'id', {
get: () => {
consoleIsOpen = true;
}
});
const verify = () => {
console.dir(el);
if (consoleIsOpen === false && consoleOpened === true) {
// console closed
window.dispatchEvent(new Event('devtools-opened'));
consoleOpened = false;
} else if (consoleIsOpen === true && consoleOpened === false) {
// console opened
window.dispatchEvent(new Event('devtools-closed'));
consoleOpened = true;
}
consoleIsOpen = false;
setTimeout(verify, 1000);
}
verify();
})();
window.addEventListener('devtools-opened', ()=>{console.log('opened')});
window.addEventListener('devtools-closed', ()=>{console.log('closed')});
Here is a code that worked for me.
This solution works like a charm
https://github.com/sindresorhus/devtools-detect
if you are not using modules - disable lines
// if (typeof module !== 'undefined' && module.exports) {
// module.exports = devtools;
// } else {
window.devtools = devtools;
// }
and result is then here
window.devtools.isOpen
I for my project use the blur event.
function yourFunction() {}
window.addEventListener('blur',(e)=>{e.preventDefault(); yourFunction()})
This will execute yourFunction when the window loses focus.
For instance when someone opens the DevTools.
Okay seems like it also fires when you try to access a different window... so maybe not the best solution.
Maybe pair it with looking at the width of the browser.
If it chainged you can be pretty sure about it I think

Do we have to create new popup every time there is an update on google crome?

Do we have to create new popup if google crome updated or we can continue with the older one.
No one is sure what you're asking, but I'm going to take a stab at it. I believe you're asking if you have to use a new popup every time an advertisement is changed? If that is the case, the answer is no, you don't always have to have a new popup. HOWEVER, if the window was closed by the user, a new popup will have to be created. The following code will bring a named window to the front:
function GetAdWindow() {
// Change the window.open parameters to your liking
var AdWindow = window.open("", "AdWindow", "toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=no,width=500,height=500");
return AdWindow;
}
After that, you have to determine if the page is blank, or already has an advertisement on it.
function UpdateAd(){
var AdWindow = GetAdWindow();
// If the AdWindow wasn't populated (meaning it was closed)
if (AdWindow.location.href === "about:blank") {
AdWindow.location = /*ADVERTISEMENT URL*/
} else {
// DO WHATEVER YOU WANT IF THE WINDOW HAD CONTENT
}
}
If you asking if your popup will go away if Chrome has an update, the answer is yes. Chrome as a whole will shot down and close all of the windows, then start back up clean.

Strange behaviour on custom NavBar for Titanium

First of all, please don't recommend me to use the native iOS/Android objects, this is a test about custom controls and I need it to work.
I'm encountering a strange behavior while using a custom Navbar in Android or iOS. All seems to be right until I close a window directly (by code) in the custom navBar. The secont time I open another window with the navBar, the old objects (label, buttons, etc.) are still there.
I post an example:
First, from a main window I call the AddForm in the NavBar:
var ui = require('navigation');
var nav = ui.createNavigatorGroup();
Alloy.Globals.navBar = nav;
nav.open(winAddPill, {animated: true});
When user press ADD button (you can't see, is in bottom of a form), I autoclose the window in the nav, after save the data, with this code:
Alloy.Globals.navBar.close($.win);
If I do that, when now I call another window, e.g., show info (which has a DELETE button in right), the title label is mixed with previous window:
Alloy.Globals.navBar.open(winPill, {animated: true});
As you can see, all is mixed, this is what must be shown instead:
If I continue to open new windows, all is still mixing.
Any help to avoid this behavior? I was fighting with this problem 4 days and don't find the solution.
Finally, the custom navBar that I'm using:
exports.createNavigatorGroup = function() {
var me = {};
var navViews = []; // A stack of navigation bars
var navView;
function pushNavBar() {
navView = Ti.UI.createView({
top: 0,
height: 44,
backgroundColor: '#BBB'
});
navViews.push(navView);
};
function popNavBar() {
navViews.pop();
navView = navViews[navViews.length - 1];
};
// Make sure we always have a navView available to prepare
pushNavBar();
me.open = function(win) {
navView.add(Ti.UI.createLabel({
text: win.title,
color: 'black'
}));
navView.win = win;
win.add(navView);
win.navBarHidden = true;
win.open();
// Prepare for the next window
pushNavBar();
};
me.close = function(win) {
if (navViews.length > 1) {
// Close the window on this nav
popNavBar();
win.close();
}
};
return me;
};
Also I added a simple and runable project in GitHub with only 3 empty windows for testing. You can see the question here and the project is here.
I found the f***g problem!!!
I analized with detail the code and found it. All the problem resides in that a new navView is always prepared for config new objects, so, lets say, we have 2 windows opened, then we have 3 navViews. The number 3 is clear, nothing inside, just ready to setLeftButton before open new window with it.
But if we close the actual window, with the navView 2 with objects, the code makes "popNavView" that only remove the last (empty) navView 3 and SETS the actual navView 2 as ready to use... with all its actual objects inside.
The simple solution is... remove it after set, with this simple line inside popNavBar:
function popNavBar() {
navViews.pop();
navView = navViews[navViews.length - 1];
navView.removeAllChildren();
};
I will re-do the github code to let it available for others who wants to use a functional custom NavBar.

How can I detect if a browser is blocking a popup?

Occasionally, I've come across a webpage that tries to pop open a new window (for user input, or something important), but the popup blocker prevents this from happening.
What methods can the calling window use to make sure the new window launched properly?
If you use JavaScript to open the popup, you can use something like this:
var newWin = window.open(url);
if(!newWin || newWin.closed || typeof newWin.closed=='undefined')
{
//POPUP BLOCKED
}
I tried a number of the examples above, but I could not get them to work with Chrome. This simple approach seems to work with Chrome 39, Firefox 34, Safari 5.1.7, and IE 11. Here is the snippet of code from our JS library.
openPopUp: function(urlToOpen) {
var popup_window=window.open(urlToOpen,"myWindow","toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, copyhistory=yes, width=400, height=400");
try {
popup_window.focus();
} catch (e) {
alert("Pop-up Blocker is enabled! Please add this site to your exception list.");
}
}
Update:
Popups exist from really ancient times. The initial idea was to show another content without closing the main window. As of now, there are other ways to do that: JavaScript is able to send requests for server, so popups are rarely used. But sometimes they are still handy.
In the past evil sites abused popups a lot. A bad page could open tons of popup windows with ads. So now most browsers try to block popups and protect the user.
Most browsers block popups if they are called outside of user-triggered event handlers like onclick.
If you think about it, that’s a bit tricky. If the code is directly in an onclick handler, then that’s easy. But what is the popup opens in setTimeout?
Try this code:
// open after 3 seconds
setTimeout(() => window.open('http://google.com'), 3000);
The popup opens in Chrome, but gets blocked in Firefox.
…And this works in Firefox too:
// open after 1 seconds
setTimeout(() => window.open('http://google.com'), 1000);
The difference is that Firefox treats a timeout of 2000ms or less are acceptable, but after it – removes the “trust”, assuming that now it’s “outside of the user action”. So the first one is blocked, and the second one is not.
Original answer which was current 2012:
This solution for popup blocker checking has been tested in FF (v11),
Safari (v6), Chrome (v23.0.127.95) & IE (v7 & v9). Update the
displayError function to handle the error message as you see fit.
var popupBlockerChecker = {
check: function(popup_window){
var scope = this;
if (popup_window) {
if(/chrome/.test(navigator.userAgent.toLowerCase())){
setTimeout(function () {
scope.is_popup_blocked(scope, popup_window);
},200);
}else{
popup_window.onload = function () {
scope.is_popup_blocked(scope, popup_window);
};
}
} else {
scope.displayError();
}
},
is_popup_blocked: function(scope, popup_window){
if ((popup_window.innerHeight > 0)==false){
scope.displayError();
}
},
displayError: function(){
alert("Popup Blocker is enabled! Please add this site to your exception list.");
}
};
Usage:
var popup = window.open("http://www.google.ca", '_blank');
popupBlockerChecker.check(popup);
Hope this helps! :)
One "solution" that will always work regardless of browser company or version is to simply put a warning message on the screen, somewhere close to the control that will create a pop-up, that politely warns the user that the action requires a pop-up and to please enable them for the site.
I know it's not fancy or anything, but it can't get any simpler and only requires about 5 minutes testing, then you can move on to other nightmares.
Once the user has allowed pop-ups for your site, it would also be considerate if you don't overdo the pop-ups. The last thing you want to do is annoy your visitors.
I've tried lots of solutions, but the only one I could come up with that also worked with uBlock Origin, was by utilising a timeout to check the closed status of the popup.
function popup (url, width, height) {
const left = (window.screen.width / 2) - (width / 2)
const top = (window.screen.height / 2) - (height / 2)
let opener = window.open(url, '', `menubar=no, toolbar=no, status=no, resizable=yes, scrollbars=yes, width=${width},height=${height},top=${top},left=${left}`)
window.setTimeout(() => {
if (!opener || opener.closed || typeof opener.closed === 'undefined') {
console.log('Not allowed...') // Do something here.
}
}, 1000)
}
Obviously this is a hack; like all solutions to this problem.
You need to provide enough time in your setTimeout to account for the initial opening and closing, so it's never going to be thoroughly accurate. It will be a position of trial and error.
Add this to your list of attempts.
I combined #Kevin B and #DanielB's solutions.
This is much simpler.
var isPopupBlockerActivated = function(popupWindow) {
if (popupWindow) {
if (/chrome/.test(navigator.userAgent.toLowerCase())) {
try {
popupWindow.focus();
} catch (e) {
return true;
}
} else {
popupWindow.onload = function() {
return (popupWindow.innerHeight > 0) === false;
};
}
} else {
return true;
}
return false;
};
Usage:
var popup = window.open('https://www.google.com', '_blank');
if (isPopupBlockerActivated(popup)) {
// Do what you want.
}
A simple approach if you own the child code as well, would be to create a simple variable in its html as below:
<script>
var magicNumber = 49;
</script>
And then check its existence from parent something similar to following:
// Create the window with login URL.
let openedWindow = window.open(URL_HERE);
// Check this magic number after some time, if it exists then your window exists
setTimeout(() => {
if (openedWindow["magicNumber"] !== 32) {
console.error("Window open was blocked");
}
}, 1500);
We wait for some time to make sure that webpage has been loaded, and check its existence.
Obviously, if the window did not load after 1500ms then the variable would still be undefined.
For some popup blockers this don't work but i use it as basic solution and add try {} catch
try {
const newWindow = window.open(url, '_blank');
if (!newWindow || newWindow.closed || typeof newWindow.closed == 'undefined') {
return null;
}
(newWindow as Window).window.focus();
newWindow.addEventListener('load', function () {
console.info('Please allow popups for this website')
})
return newWindow;
} catch (e) {
return null;
}
This will try to call addEventListaner function but if popup is not open then it will break and go to catch, then ask if its object or null and run rest of code.
By using onbeforeunload event we can check as follows
function popup()
{
var chk=false;
var win1=window.open();
win1.onbeforeunload=()=>{
var win2=window.open();
win2.onbeforeunload=()=>{
chk=true;
};
win2.close();
};
win1.close();
return chk;
}
it will open 2 black windows in background
the function returns boolean value.

Categories