lifebalance
lifebalance

Reputation: 1927

JavaScript bookmarklet code to get URL of tab that was launched from current tab

I am trying to develop a bookmarklet. The purpose of the bookmarklet is to display the URL of both the current tab and the new tab that was launched as a result of a window.open call. To simplify things, assume that the launcher.com launches a random URL to visit.

function getBothURLs() { 
    var currentURL, newWin;

    function launchNew () {
        currentURL = window.location.href; 
        newWin     = window.open("https://www.launcher.com");
    }

    launchNew();
    alert(currentURL); 
    alert(newWin.location.href); // displays 'about:blank'
}

I am unable to get the URL of the newly launched tab. The alert() (at the very end of the function below) does not correctly display the newly launch tab's URL; instead it displays

 about:blank

When I was troubleshooting this within the Chrome console, I moved the definition of var currentURL, newWin to outside the scope of the getTwoURLs() function. When I invoked the function getBothURLs() from within the console, both currentURL and newWin had valid data.

How should the function getBothURLs() be modified to achieve the desired purpose?

Upvotes: 1

Views: 654

Answers (1)

riyaz-ali
riyaz-ali

Reputation: 9102

A note on window.open from MDN:

...remote URLs won't load immediately. When window.open() returns, the window always contains about:blank. The actual fetching of the URL is deferred and starts after the current script block finishes executing...

In the above case the current blocks ends with the getBothURLs() function, but you attempt to check the new URL within that block itself, and according to the quote above, you see the about:blank url.
To fix this just defer the lookup until the next task. You can use something like setTimeout to post the lookup onto the next task or, even better, use Promises if you wish to return the value from the function.

A sample implementation could look like:

function getBothURLs() {
  return new Promise((resolve) => {
    var newWin = window.open("//www.stackoverflow.com");
    setTimeout(() => resolve(newWin))
  }).then((win) => {
    return new Promise((resolve, reject) => {
       var check = setInterval(() => {
         try { 
           if(win.location.href !== "about:blank"){
               clearInterval(check);
               resolve(win.location.href)
           }
         } catch(e) {
           clearInterval(check);
           reject(e);
         }
       }, 50)
     })
   })
}

getBothURLs().then(url => console.log(url))

Although, the above mentioned solution works, I would still recommend that you store new window's URL in a variable and then call open with that variable.

Update 1:

This example snippet uses the non-promise callback version that could return both the urls. Although, it's possible to modify the promise version to return two urls as well but since the OP asked for a non-promise based version in the comments so I provided the new snippet. Have a look:

function getBothURLs(callback){
  var current = window.location.href;
  var win = window.open("https://stackoverflow.com");
  var check =  setInterval(() => {
    try {
      if(win.location.href !== "about:blank"){
        clearInterval(check);
        callback(null, current, win.location.href)
      }
    } catch(e) {
      clearInterval(check);
      callback(e);
    }
  }, 50);
}

getBothURLs((err, _cur, _new) => {
  if(err){
    // some error occurred, probably a cross-origin access
    console.error("Failed to get URL", err);
    return;
  }

  console.log(`Current: ${_cur} New: ${_new}`);
})

Upvotes: 1

Related Questions