How to override window.open? - javascript

I was wodering, is it possible to override window.open? I want to a add delay to every window.open call
Let's say one piece of code opens window using onClick, the other one using window.open, so is it possible to add like setTimeout to global window.open?

First save a reference to window.open, then overwrite it with your own function that calls the saved reference after the timeout:
const origOpen = window.open;
window.open = (url) => {
setTimeout(() => {
origOpen(url);
}, 1000);
};
window.open('https://www.google.com');
(cannot embed into live snippet due to sandboxing constraints, but you can see a live demo here)

Related

Javascript wait for window to close before opening another

I need to open a series of popup windows, each window must be closed before the next one can be opened.
function openWindows() {
var urls = getListOfUrls();
for (let url of urls) {
openWindow(url);
// Wait for window to close before continuing.
}
}
The only way I found to make sure that a window is closed is to use a setInterval which, as I understand it, causes the function behave asynchronously.
Any idea on how I can achieve this?
Potential alternate suggestion
Without more information, it sounds like what you're trying to accomplish can be completely automated using puppeteer and in-page scripting. If the URLs that you are visiting aren't all in the same origin, then this is the only method which will work (the solution below will not apply).
Interpretation of question
However, let's say that you need to manually perform some tasks on each page in order (one at a time) for whatever reason (maybe the pages you're retrieving often change their DOM in a way that keeps breaking your scripts), but you want to skip the rigor of serially opening the URLs in new tabs, so that you can just focus on the manual tasks.
Solution
JavaScript web APIs don't provide a way to check for the closure of a window (a script would no longer be running at that point), but the last event that you can respond to is the unload event, and using it would look something like this:
References:
Window
Window: unload event
Window.open()
Same-origin policy
async function openEachWindowAfterThePreviousUnloads (urls) {
for (const url of urls) {
console.log(`Opening URL: "${url}"`);
const target = '_blank';
const initialTime = performance.now();
const windowProxy = window.open(url, target);
if (!windowProxy) {
throw new Error(`Could not get window proxy for URL: "${url}"`);
}
await new Promise(resolve => {
windowProxy.addEventListener('unload', ev => {
const delta = performance.now() - initialTime;
const thresholdMs = 1000;
if (delta < thresholdMs) return;
resolve();
});
});
}
}
const tags = [
'javascript',
'puppeteer',
];
const urls = tags.map(tag => `https://stackoverflow.com/questions/tagged/${tag}`);
openEachWindowAfterThePreviousUnloads(urls);
Code in TypeScript Playground
Caveats:
The script will fail if any of the following is not true:
Every URL is in the same origin as that of the invoking window
If your browser blocks pop-ups, the page where you run the script is allowed to create pop-ups. Example error:
You can try the code above in your browser JS console on this page, and (as long as https://stackoverflow.com is allowed to create popups) it should work.

Open new (popup) window to answer Twilio call

I'm using the Twilio JavaScript SDK to place and receive calls in the browser. As part of this I have a requirement to make and receive calls in a new popup window. This is so that a user can continue browsing the site without disconnecting the call.
I have got this working for outgoing calls (a user clicks a number, and on the back of this I call window.open which initiates the call).
However for incoming calls, I'm attempting to do the following in the initiating browser window:
Twilio.Device.incoming(function (connection) {
$('#callPopup').show();
$('.js-answer-call').on('click', function (event) {
event.preventDefault();
var receiveCallWindow = window.open('/call/incoming', '', 'width=350,height=200');
receiveCallWindow.connection = connection;
$('#callPopup').hide();
});
$('.js-reject-call').on('click', function (event) {
event.preventDefault();
connection.reject();
$('#callPopup').hide();
});
});
This passes the connection object to the popup window, and then the popup window runs the following code:
var connection = window.connection;
$(document).ready(function () {
connection.accept();
});
This does answer the call, however the call context is still within the parent window and if a user navigates away from that page it will end the call.
I understand that I can achieve this via a master iframe containing just the call logic, with the main web app inside the frame, however I think that's a very messy implementation and want to avoid that.
Twilio developer evangelist here.
Your problem in this case is indeed that the call context is in the parent window. The only thing that comes to mind to me right now is to popup the call window when your user logs on and is prepared to answer calls and then initialise the Twilio.Device in the popup window.
You could still connect this popup window to the code for outbound calls too.
Does this help at all?

Calling location.reload() and location.assign() sequentially

I'm trying to reload a page and then access a file download url in javascript like so:
function reloadAndDownload() {
location.reload();
location.assign(fileDownloadURL);
}
I find that in the above example, only the "location.assign()" seems to execute.
If I have this:
function reloadAndDownload() {
location.assign(fileDownloadURL);
location.reload();
}
then only the "location.reload()" seems to execute. Is it possible to call both these functions sequentially as described and have them both execute?
It's not possible. Javascript runs in window, and each of location functions triggers its reload. You may open a new window.

How to sleep in a firefox extension without using setTimeout?

I am trying to open a pop-up window, wait X seconds and then close the popup window.
(The use case is sending a notification to a webapp - but we can't just do a GET request as it needs to be in the same session so we can use the login session)
I can't use setTimeout as we can't use it in add-ons/extensions
How can I get similar functionality without resorting to chewing up CPU cycles, which obviously causes a noticeable lag?
You can use the timers module provided by the SDK instead of nsITimer for the same kind of setTimeout/setInterval functionality provided in browsers
let { setTimeout } = require('sdk/timers');
function openPopup () {}
setTimeout(openPopup, 3000);
You can use nsITimer.
A basic example is below but you can find more information (including the use of Components.interfaces.nsITimer.TYPE_REPEATING_SLACK as an alternative to setInterval) on the relevant documentation page at https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsITimer
// we need an nsITimerCallback compatible interface for the callbacks.
var event = {
notify: function(timer) {
alert("Fire!");
}
}
// Create the timer...
var timer = Components.classes["#mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
// initialize it to call event.notify() once after exactly ten seconds.
timer.initWithCallback(event,10000, Components.interfaces.nsITimer.TYPE_ONE_SHOT);

setTimeout to open a new window in response to a click

I've noticed that when doing
$(".sitelink_external").click(function(e){
e.preventDefault();
window.open(redirectUrl,'_blank')
});
it opens a new tab or window, without calling the pop-up blocker of Chrome, Firefox or IE.
However, I want to create a redirect so that the user will be able to regret, making a timer for the link, and if I do like this:
$(".sitelink_external").click(function(e){
e.preventDefault();
setTimeout("window.open(redirectUrl,'_blank')", timer * 1000);
});
It calls the popup blocker, and doesn't open the popup the way I want, any idea how to resolve this?
EDIT: the answers are great, but don't resolve the problem, as it was working before as well in the same manner.
You can create a really bad performance synchronous timeout function:
function synchronousTimeout (timeout, handler) {
const start = new Date().getTime()
while ((new Date().getTime() - start) < timeout) {}
handler()
}
And then simply use it with your click handler
$(".sitelink_external").click(function(e){
e.preventDefault();
synchronousTimeout(timer * 1000, () => window.open(redirectUrl,'_blank'));
});
EDIT: I just realised that this questions was from YEAAAARS before, wow :D
Change the setTimeout call to do this instead:
setTimeout(function() { window.open(redirectUrl,'_blank') }, timer * 1000);
You can't pass a variable the way you were doing it (and it is generally better to pass a function rather than a string that will be eval'd)

Categories