Relative to absolute links with JavaScript

March 17th, 2009. Tagged: JavaScript

I was toying with a completely different thing and specifically a Yahoo service that gives you the ability to use HTML as data and then lets you use xpath to query this data. I came up with a somewhat interesting idea (will post tomorrow, too late now), but all of a sudden I realized I need to convert relative links to absolute ones. I thought it's just a trivial thing (I mean how hard could it be) but then it turns out there are these little edge cases...

Anyway, I came up with something and posting here in case someone else might need it (or even me, for example two years from now. Hmm, will there be URLs in the future, in the distant 2011, or we'll all be just pure non-material consciousness ?)

So, the test page is here

And the actual code (also on github) is as follows:

function toAbs(link, host) {
 
  var lparts = link.split('/');
  if (/http:|https:|ftp:/.test(lparts[0])) {
    // already abs, return
    return link;
  }
 
  var i, hparts = host.split('/');
  if (hparts.length > 3) {
    hparts.pop(); // strip trailing thingie, either scriptname or blank 
  }
      
  if (lparts[0] === '') { // like "/here/dude.png"
    host = hparts[0] + '//' + hparts[2];
    hparts = host.split('/'); // re-split host parts from scheme and domain only
    delete lparts[0];
  }
 
  for(i = 0; i < lparts.length; i++) {
    if (lparts[i] === '..') {
      // remove the previous dir level, if exists
      if (typeof lparts[i - 1] !== 'undefined') { 
        delete lparts[i - 1];
      } else if (hparts.length > 3) { // at least leave scheme and domain
        hparts.pop(); // stip one dir off the host for each /../
      }
      delete lparts[i];
    }
    if(lparts[i] === '.') {
      delete lparts[i];
    }
  }
 
  // remove deleted
  var newlinkparts = [];
  for (i = 0; i < lparts.length; i++) {
    if (typeof lparts[i] !== 'undefined') {
      newlinkparts[newlinkparts.length] = lparts[i];
    }
  }
 
  return hparts.join('/') + '/' + newlinkparts.join('/');
 
}

Update: added a check for ./ in the URLs thanks to QA from BoĊĦtjan

Tell your friends about this post: Facebook, Twitter, Google+

Sorry, comments disabled and hidden due to excessive spam. Working on restoring the existing comments...

Meanwhile, hit me up on twitter @stoyanstefanov