// =========================================================================================
// HANDLE EXTERNAL / POPUP LINKS
// - To be fully XHTML, link elements shouldn't utilise the "target" attribute, so it's
//   been taken out of the generated markup and instead we hook up the click and keypress
//   handlers to popup a window for us on links with "rel" attrib set to "external".
//    However, this means that "referrer" header information isn't passed properly by all
//   browsers (IE) so stats get screwed up. "target" is still a valid DOM setting, so we're
//   going to cheat and make the click and keypress handlers set "target" to "_blank" and
//   let the window open, then undo the "target" setting (so even Firebug's little indicator
//   in the status bar will flip back to valid).
// NB: "rel" attributes can have multiple values, space separated - eg. "external nofollow"
// =========================================================================================
function externalLinks()
{
	// Loop through all anchor / link elements of page with "rel" attrib set to "external"
	// and adjust intercept their onclick handler (if any) such that it will call the
	// TargetAttribCheat function first, which will set the link's "target" attrib to
	// "blank" and then set it back to its previous value (if any) 100ms later. This
	// means any onclick code that gets called better be quicker! Displaying an alert
	// box in the onclick handler will cause issues, for example.
	if (!document.getElementsByTagName)
		return;
	var arrLinks = document.getElementsByTagName("a");
	for (var i = 0; i < arrLinks.length; i++)
	{
		var objLink = arrLinks[i];
		if ((objLink.getAttribute("href")) 
		&& ((" " + objLink.getAttribute("rel") + " ").indexOf(" external ") !== -1))
		{
			if (objLink.title.indexOf("opens in a") == -1)
				objLink.title += " Link opens in a new window";
			objLink.onclick = GenNewFunc(
				TargetAttribCheat,
				(typeof(objLink.onclick) === "undefined") ? null : objLink.onclick);
		}
	}
	
	// This methods returns a function wrapping old and new onclick handlers
	function GenNewFunc(fncNew, fncOld)
	{
		// When we get here (see above), we'll have a reference to the containing element
		// which we don't want in the click handler (circular references issue for garbage
		// collection in IE), so we'll explicitly set objLink to null here.
		var objLink = null;
		return function()
		{
			fncNew.apply(this, arguments);
			if (fncOld != null)
				return fncOld.apply(this, arguments);
		};
	}
	
	// This method temporarily assigns "_blank" value to "target" attribute, then resets
	// it back after a delay
	function TargetAttribCheat(e, bEnable, bAutoDisable, intAutoDisTimeout)
	{
		// Try to access the source element that raised this call
		e = e || window.event;
		if (!e)
			return;
		var objSrc = e.srcElement || e.target;
		if (!objSrc)
			return;
			
		// If we've got an image within the link element then that image may appear as the
		// source element, rather than the actual link. So we may need to head up the chain
		// until we get the original anchor.
		while (String(objSrc.tagName).toUpperCase() !== "A")
		{
			// Check we've not hit the top of the tree
			if ((!objSrc) || (objSrc.parentNode === objSrc))
				return;
			objSrc = objSrc.parentNode;
		}

		/*
			bEnable, bAutoDisable and intAutoDisTimeout are optional, defaulting
			to True, True and 100, respectively.
				bEnable:
					True => Set "target" attrib to "_blank"
					False => Reset to previous value
				bAutoDisable:
					True => After a timeout, automatically re-call this method with bEnable
					set to False to reset the "target" attribute's value. Only relevant when
					bEnable is True.
				intAutoDisTimeout:
					Override the default AutoDisable timeout. Only applicable when bEnable
					and bAutoDisable are True.
		*/
		if ((typeof(bEnable) === "undefined") || (bEnable !== false))
			bEnable = true;
		if ((typeof(bAutoDisable) === "undefined") || (bAutoDisable !== false))
			bAutoDisable = true;
		if ((typeof(intAutoDisTimeout) === "undefined") || isNaN(intAutoDisTimeout))
			intAutoDisTimeout = 100;
		Work(objSrc, bEnable, bAutoDisable, intAutoDisTimeout);
	
		// Perform the element manipulation
		function Work(objSrc, bEnable, bAutoDisable, intAutoDisTimeout)
		{
			if (bEnable)
			{
				// In case this method gets called several times in succession, don't allow
				// a previously recorded "target" value to be overwritten.
				if (typeof(objSrc.targetOldNM) === "undefined")
				{
					if (typeof(objSrc.target) === "undefined")
						objSrc.targetOldNM = "";
					else
						objSrc.targetOldNM = objSrc.target;
				}
				// Set new "target" value and set up AutoDisable function (if required)
				objSrc.target = "_blank";
				if (bAutoDisable)
					setTimeout(function() { Work(objSrc, false); }, intAutoDisTimeout);
			}
			else
			{
				if (typeof(objSrc.targetOldNM) !== "undefined")
				{
					objSrc.target = objSrc.targetOldNM;
					delete objSrc["targetOldNM"];
				}
			}
		}
	}
}
