Using window.open in an async function in Firefox and Safari - javascript

The application I work on integrates with some platforms with some strict security policies when it comes to user authentication, and as such authentication from our side has to be handled a bit differently as well. The details here aren't terribly important.
I'm working on a new feature now where a user can open some items from a list, but from a UX perspective it would make the most sense to open these up in new tabs, since users will want to open a lot of them at once without having to navigate back to the list and find their place within it again.
So to get this working, our API has a redirects endpoint that handles the authentication. Implementation details aren't important, it's just important to know that this endpoint will receive a URL that should be navigated to (supplied from our UI), and it'll spit back out a redirect URL with a token.
As such, I've gone with the following function which gets called when a button is clicked by the user
async function openInNewTab() {
// $ajax is an axios instance that calls the endpoint
const { url } = await $ajax.post('/redirects', {
data: {
url: "myurl.com/route/to/go/to",
//...
}
});
window.open(url)
}
As you can see, it's very simple, it gets the redirect URL from our API and tries to open that URL in a new tab. This works in Chrome, however it doesn't work in Firefox or Safari, prompting the user that a popup was blocked.
I'm well aware that browser have a number of rules regarding popups and when they're blocked, however in this instance this action is being initiated by user interaction via a button click, the only problem being that the function getting called is asynchronous.
Is there any way to make this work in Firefox and Safari? The function simply doesn't work well enough in realistic network speeds without it being asynchronous, and with the way our application works there's no way for us to circumvent the redirect URL with something like a target="_blank" in a link, that would fail to authenticate properly.

There's 2 potential workarounds that I ended up with here.
They're both fairly similar, however from my testing it seems Safari is the strictest when it comes to parsing events as popups.
The one that works in all major browsers (Chromium-based ones, Firefox and Safari), but feels a bit hacky.
Found this here: https://stackoverflow.com/a/70463940/8610114
const { url } = await $ajax.post('/redirects', {
data: {
url: "myurl.com/route/to/go/to",
//...
}
});
setTimeout(() => {
window.open(url, "_blank");
});
And the other solution, although this one doesn't seem like it works in Safari consistently, as it gets blocked sometimes (seemingly randomly)
const newWindow = window.open('about:blank', '_blank');
const { url } = await $ajax.post('/redirects', {
data: {
url: "myurl.com/route/to/go/to",
//...
}
});
newWindow.location.href = url;

Related

React: window.close() working in Chrome but not Firefox

I have a single-page react app hosted on github pages, which comes with many limitations. In order to get my "Login with Twitter" flow working, I found it was necessary to open the dynamic twitter login url in a new tab, give the Twitter API an endpoint on my backend as the callback URL, and then have my backend redirect the user to the root url of my frontend client with the generated JWT token in the URL as a query (/?token=abcd1234). I then have some code on the landing page of my client that looks like this:
useEffect(() => {
// at /?close, just close the window
if (props.location.search === '?close') {
window.close()
closeWindow()
setShowCloseMessage(true)
// at /?token, save the token to localstorage, then close the window
} else if (tokenUrlRE.test(props.location.search)) {
const token = props.location.search.match(tokenRE)[0]
localStorage.setItem('token', token)
window.close()
closeWindow()
setShowCloseMessage(true)
}
}, [])
This works fine in Chrome, but not Firefox - perhaps Firefox is more stringent about requiring that Windows only be closed by the script that opened them, and Chrome allows any script on the same domain that opened a window to close it?
Anyway, several other answers here on Stackexchange recommended the following code, which I added inside the closeWindow() function appearing in the above code:
function closeWindow() {
console.log('clicked close')
window.open('', '_parent', '')
window.close()
}
But this also did not work in Firefox.
Furthermore, this additional solution I found caused React to crash:
open(location, '_self').close()
Is there any way to accomplish what I want with Firefox? For the time being I have simply used that showClose state variable seen in the first code block to display a "Sign-in successful, please return to the previous tab" message, but this is less than ideal.

Trying to open window.open a page in ajax call response

i am trying to open window.open a page in ajax call response but its not work, but when i removed window.open line and uncomment alert then alert is working.
$.ajax({
url: "/xyz/xyxkk",
type: 'Get',
success: function (resp) {
window.open("https://www.w3schools.com");
//alert('hi');
if (resp) {
}
else {
alert('Sorry unable to do');
}
}
});
actually my requirement is page open as window popup
Comment would fit better but not enough reputation, sorry.
Due to the ever lasting battles between browsers and intrusive ads, all js functions that can open new tabs or windows have been severely limited for a long time now. You can't just randomly open new pages or windows.
Generally you can get around this, by 'associating' the window.open to a click event or similar user input. Else your solutions will probably break in the future, even if you get it working for the moment.
Try calling different elements of your code with a .onclick() to see what is allowed. Don't forget to check at least Chrome and Firefox, and also try a few adblockers. If your solution works reliably under all of those you should be good for future adwars to come.

Page loading takes time

My website uses ajax to fetch and display data often..Everytime a request is made , it displays data fast but keep on loading. I'm unable to click on anything else, as once the psge is fully loaded, only then I can interact with the page.
I checked the console and I would like to understand what causes the following :
As I clicked on one of the links marked in red above, I got this in the console too.I don't have any link to facebook share or like button. I would like to understand what causes this error , please.
(function () {
if (window.g_clrDimensionsSent) return;
window.g_clrDimensionsSent = true;
var data = new FormData();
data.append('windowWidth', window.innerWidth);
data.append('windowHeight', window.innerHeight);
data.append('headHtml', window.document.head.outerHTML);
data.append('bodyHtml', window.document.body.outerHTML);
var xhr = new XMLHttpRequest();
xhr.open('POST', document.location.protocol + '//__fake__.com');
xhr.send(data);
})()
It looks like you are connecting from your local machine and not the website for which your Facebook page is set up. Have you checked the settings of your Facebook app?
Usually you should use your hosts file to rather mimmick your live url, or you must set the Canvas, Public etc URLs as "localhost" and not your live website.
As for the parts in RED, your site is making a post to "fake.com"... which is most likely malware in your browser, unless you specifically coded calls to post to that URL?
Run malware bytes to confirm, or disable all your plugins in your browser. The "VM" part means its the browser throwing the error, and not the website. Do a check to see if you also get those errors on other pages.

How do I detect if window.location failed?

How do I check if a call to window.location failed because the given URL was invalid, etc? Is there some event I can set on the window object or on some other object that can catch this?
Finally got it to work using a "workaround" that is not a generic solution as I originally hoped:
I am using the fact that the link I am trying to open is a custom url scheme (e.g. myxx://localhost) on mobile, and if it fails, the action I want to perform is a redirection to a standard appstore URL (os-specific). The workaround tries to open the custom URL, and if it fails, the timeout function kicks in shortly after, and opens an alternative url:
setTimeout(function() { window.location=alternateUrl; }, 25);
window.location = customUrl;
The downside is that when the customURL fails, a standard safari browser shows a message box that the site could not be opened, but at least it still redirects the user to the appstore.
Not really possible, because when window.location = someURL is executed, before the URL is even tested, your document is removed from the window. You have no code remaining that could test if it worked.
If the link is on the same origin, you may issue an XMLHttpRequest to test if the page is reachable but there doesn't seem to be a way to test if a page isn't requestable just due to cross origin request or because the URL is wrong.
For a general document, I don't know any way to test if a foreign origin page is reachable (but it can be done for an image using the onload event handler).
you can check if page exists using ajax. didn't test code, but it should work.
var rekuest= new XMLHttpRequest();
rekuest.open('GET', 'http://www.thisdoesnotexits.org', true);
rekuest.send();
if (rekuest.status === "404") {alert("not exist!"); }

How to display error (text/html) response to an AJAX/getJSON request?

My situation is, I'm developing a little web app where the server provides dynamic JSON responses. The server is built on cherrypy. Sometimes, there is a bug in the code creating the JSON data, which throws, and cherrypy catches it and serves back a 500-error with a full HTML page detailing the exception. (That is, the response has everything: <!doctype..><html><head>...</head><body>...</body></html>)
But because the request is AJAX, it doesn't get displayed.
I can intercept this error easily enough, and look at it in the dev tools; but what I'd like to do (to ease debugging) is open a new page (as if user had followed a link) and display that response in the browser. I tried
window.open('', '_self');
$(document).html(jqXHR.responseText);
but I just get a blank page. I suppose I could store the error text and serve it up in a second request to the server, but is there a cleaner way?
To follow up, the final code that worked was this:
.error(function(jqXHR, textStatus, errorThrown) {
$(window).bind('unload', function() { document.write(jqXHR.responseText); } );
var win = window.open('', '_self');
return false;
});
Not sure if that final return false is necessary but it seems good form.
Following up again: the above code worked reliably in Opera. I thought I had seen it working in Webkit as well, but I started noticing that it wasn't; and on further testing, it wasn't working for Firefox either.
What I found that worked in all three platforms was this:
document.open('text/html', true);
document.write(jqXHR.responseText);
document.close();
Don't have to open another window or bind events; just re-open the document and stuff the text in there.
Well, here I am again. The above technique either stopped working or I was tripping when I said it ever worked at all. Chrome, in particular, doesn't seem to have document.open defined.
But! I just found a nifty technique that seems to work everywhere:
errtext = 'data:text/html;base64,' + window.btoa(jqXHR.responseText);
window.open(errtext, '_self');
This simply converts the response into a fully self-contained data: URL and opens it in the window.
Try this:
var win = window.open('', '_self');
win.document.getElementsByTagName('Body')[0].innerText = jqXHR.responseText;

Categories