qualifyHREF
6th January 2009
This script takes a relative path, such as the href
attribute of a link,
and converts it into a fully-qualified URL.
The conversion is based by default
on the address of the current page, but it can also work
with a context defined by a <base>
element,
or the location of another resource, such as the document in an <iframe>
.
The script comes in particularly useful for normalizing the difference in
href
and src
values
between Internet Explorer and other browsers, as discussed in a blog post I wrote for
SitePoint,
Dealing with unqualified HREF values
Get the script
Download the zipfile [1K] and unzip it into your site directory, then you can either include the script on your page as it is:
<script type="text/javascript" src="qualifyhref.js"></script>
or copy the code into another script, and work with it from there:
//QH1.0 :: qualifyHREF by brothercake - http://www.brothercake.com/
//qualify an HREF to form a complete URI
function qualifyHREF(href, context)
{
//get the current document location href
var here = document.location.href;
//look for a base element to use instead
var bases = document.getElementsByTagName('base');
if(bases.length > 0)
{
var basehref = bases[0].getAttribute('href');
if(basehref && basehref != '')
{
here = basehref;
}
}
//if the context argument is present and non-empty string, use that instead
if(typeof context == 'string' && context != '')
{
here = context;
}
//extract the protocol, host and path
//and create a location object with the data
var parts = here.replace('//', '/').split('/');
var loc = {
'protocol' : parts[0],
'host' : parts[1]
}
parts.splice(0, 2);
loc.pathname = '/' + parts.join('/');
//build a base URI from the protocol plus host (which includes port if applicable)
var uri = loc.protocol + '//' + loc.host;
//if the input path is relative-from-here
//just delete the ./ token to make it relative
if(/^(\.\/)([^\/]?)/.test(href))
{
href = href.replace(/^(\.\/)([^\/]?)/, '$2');
}
//if the input href is already qualified, copy it unchanged
if(/^([a-z]+)\:\/\//.test(href))
{
uri = href;
}
//or if the input href begins with a leading slash, then it's base relative
//so just add the input href to the base URI
else if(href.substr(0, 1) == '/')
{
uri += href;
}
//or if it's an up-reference we need to compute the path
else if(/^((\.\.\/)+)([^\/].*$)/.test(href))
{
//get the last part of the path, minus up-references
var lastpath = href.match(/^((\.\.\/)+)([^\/].*$)/);
lastpath = lastpath[lastpath.length - 1];
//count the number of up-references
var references = href.split('../').length - 1;
//get the path parts and delete the last one (this page or directory)
var parts = loc.pathname.split('/');
parts = parts.splice(0, parts.length - 1);
//for each of the up-references, delete the last part of the path
for(var i=0; i<references; i++)
{
parts = parts.splice(0, parts.length - 1);
}
//now rebuild the path
var path = '';
for(i=0; i<parts.length; i++)
{
if(parts[i] != '')
{
path += '/' + parts[i];
}
}
path += '/';
//and add the last part of the path
path += lastpath;
//then add the path and input href to the base URI
uri += path;
}
//otherwise it's a relative path,
else
{
//calculate the path to this directory
path = '';
parts = loc.pathname.split('/');
parts = parts.splice(0, parts.length - 1);
for(var i=0; i<parts.length; i++)
{
if(parts[i] != '')
{
path += '/' + parts[i];
}
}
path += '/';
//then add the path and input href to the base URI
uri += path + href;
}
//return the final uri
return uri;
}
Once it's in your codebase you can call it as required, storing the value it returns for further use, for example:
var src = '/images/pants.png';
var uri = qualifyHREF(src);
alert(uri); //would alert "http://www.brothercake.com/images/pants.png"
In that example, the location of this page is used as the context
for creating a qualified URL.
However we could also pass in an explicit context,
such as the location of an <iframe>
document:
var uri = qualifyHREF(src, document.frames['myIframe'].location.href);