Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open multiple pop up windows in safari 11

Since the safari 11 update on September 20 - the following code (Javascript) only opens 1 window at a time (on safari 10.1 it opens them all).

Is it possible to do this in safari 11 and if yes, how?

My code (just an example):

window.open("https://www.stackoverflow.com");
window.open("https://www.google.com");
window.open("https://www.youtube.com");

Update :

  1. The browser preferences are set to enable pop ups and to not block anything.
  2. The code works if I set a "setTimeout()" between each window open of at least 0.5 seconds - this may be because maybe the new update of safari does not want to let me "spam" the user with too many pop up windows.
like image 904
Niv Apo Avatar asked Oct 18 '25 14:10

Niv Apo


1 Answers

Update: This question and solution is still valid as of Safari 13.

First, here's the behaviour of Safari 11 I've observed from testing:

  • One popup is always allowed to open (even when the global "Block pop-ups" setting is checked). When "Block pop-up windows" is checked, access to the popup's window object is restricted (not the case when "Block pop-up windows" is unchecked).
  • As you've described, when "Block pop-up windows" is unchecked, multiple window.open calls must be delayed (>1s required in my testing).
  • When "Block pop-up windows" is checked, it seems only one popup will ever be allowed to open (despite delay used).

So, you've discovered one way to get around this: Add a delay.

Here's one more way that will allow you to open multiple popups without the need for a delay, using the knowledge that when "Block pop-up windows" is unchecked, each window may open one pop-up without a delay. With the three popups in your example in mind, here's the general flow:

  1. Open a popup (blank page) on your domain.
  2. Delegate the opening of the next popup to this popup by injecting a script that does it on load.
  3. Redirect the first popup to your desired URL.
  4. Repeat until all your pop-ups are open.

The following is what I've built to handle this flow:

/**
 * Handle the passed hrefs for Safari, which requires special/different
 * handling than other browsers. Open each one in a new window (popup)
 * and delegate the opening of the next popup to each new popup. Handle
 * Safari's global popup blocker setting and inform the primary page
 * (via postMessage) when the blocker is enabled, so a notification can
 * be shown to the user.
 *
 * @param  {Array}    hrefs             hrefs of popups to open
 * @param  {Function} safariPopupOpener Self reference. Required for
 *                                      injecting into next popup.
 * @param  {Window}   primaryWindow     Reference to the primary page
 *                                      Window object. Required for
 *                                      sending postMessage back.
 * @param  {string}   blockedMessage    Message body to send back in
 *                                      postMessage.
 */
var safariPopupOpener = function(
    hrefs,
    safariPopupOpener,
    primaryWindow,
    blockedMessage
) {
    var newWindow = window.open('//url/of/the/blank/page/on/your/domain');
    var popupOpenerScript = document.createElement('script');

        // Must add these all to the popup's window object as the
        // execution context of opener() below where they're used is the
        // next popup, not the current window
        newWindow.openAllResultHrefs = hrefs;
        newWindow.openAllResultOpener = safariPopupOpener;
        newWindow.primaryWindow = primaryWindow;
        newWindow.blockedMessage = blockedMessage;

        /**
         * Logic to inject into the popup
         */
        function opener() {
            var hrefsCopy = window.openAllResultHrefs.slice();

            // Delete the first item from the array for injecting into
            // the next popup
            hrefsCopy.shift();

            if (hrefsCopy.length > 0) {
                // Even when popups are blocked in Safari, one popup is
                // always allowed to open. However any other popups
                // opened sequentially are blocked. Also, access to the
                // one popup's window object is restricted, so this
                // tries to open the second popup, if window object is
                // restricted (which occurs before another popup is
                // opened), catches the resulting error, closes the
                // first popup and sends a message back to the primary
                // page that popups are blocked.
                try {
                    window.openAllResultOpener(
                        hrefsCopy,
                        window.openAllResultOpener,
                        window.primaryWindow,
                        window.blockedMessage
                    );
                } catch (e) {
                    // Optional: Send a message back to the primary page that
                    // popups have been blocked
                    window.primaryWindow.postMessage(
                        window.blockedMessage,
                        window.primaryWindow.origin
                    );

                    // Close the (first) popup window (first because
                    // we only reach this case when popups are blocked
                    // and we've only successfully opened one popup)
                    window.close();
                }
            }

            // Redirect to the popup href
            window.location.href = window.openAllResultHrefs[0];
        }

    // Inject the self-executing opener function so it'll run on load in
    // the opened popup
    popupOpenerScript.innerHTML = '(' + opener.toString() + '());';
    newWindow.addEventListener('load', function() {
        // Append the script to the new window's body
        this.document.body.appendChild(popupOpenerScript);
    });
}
  • Note that I'm also detecting blocking and sending a postMessage back to the primary window so it can handle the blocking (e.g. display a message to the user). So, would require a message listener on the primary page.
  • postMessage may not be necessary but I couldn't access window.opener when popups were blocked. Also probably lots of room for improvement, but I've already spent too much time on this :-))
like image 163
Matt Bennett Avatar answered Oct 20 '25 03:10

Matt Bennett



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!