/*
	linkstyler.js
	
	v2.07, 2008-05-28, Christian Augustin

*/
/*

	Set link target and className according to url resp. given className.
	
	Caveats
	- Autostyle pageUp/pageDown not supported.
	
	ToDo
	- Fully incorporate path fragment handling.
	
	Changes
	2008-05-28 cma: Bug with MetaDoc-W page group URLs fixed.
	2007-11-27 cma: Workaround for Safari bug with +U200B.
	2007-10-05 cma: Now also supports multiple link class names with autostyle ...
	2007-10-04 cma: Now supports multiple link class names (first match wins).
	2007-06-05 cma: Try/catch for HREF to circumvent JS security errors with MSIE 7.
	2007-05-29 cma: Improved checks on iconBefore/After.
	2007-05-29 cma: Styling for anchors without href.
	2007-05-28 cma: iconBefore, iconAfter and linkstylerActive added.
	2007-03-14 cma: Using array to hold preloaded images; declared 2.0!
	2007-03-14 cma: Re-inventing the wheel (okay, its only coop with msie_png_fix.htc).
	2007-02-27 cma: Breakable links added!
	2007-02-14 cma: First bugfixing.
	2007-02-13 cma: Initial version (major redesign).
	
	ToDo
	-	Image highlighting for self and same-area links.
	-	Image link (3 variants needed: image, imageOpen and imageExternal). Really?
	-	Back link (how to detect?).
	
*/

var LinkStyler = {

	types: {
		'.bin': {css: 'download', target: ''},
		'.exe': {css: 'download', target: ''},
		'.gz': {css: 'download', target: ''},
		'.hqx': {css: 'download', target: ''},
		'.pdf': {css: 'pdf', target: '_blank'},
		'.tar': {css: 'download', target: ''},
		'.txt': {css: 'text', target: '_blank'},
		'.zip': {css: 'download', target: ''},
		'mailto:': {css: 'mailto', target: ''},
		'javascript:': {css: 'javascript', target: ''},
		'open': {css: 'open', target: '_blank'},
		'external': {css: 'external', target: '_blank'},
		'pageUp': {css: 'pageUp', target: ''},
		'pageDown': {css: 'pageDown', target: ''},
		'self': {css: 'self', target: ''},
		'goto': {css: 'goto', target: ''}
	},

	autostyleEmptyClass: false, // autostyle on empty class attribute
	hoverLinkImages: true,
	breakableLinks: true,

	presets: ['types', 'autostyleEmptyClass', 'hoverLinkImages', 'breakableLinks'],

	getPresets: function() {
		if (typeof presets == 'undefined' || !presets.LinkStyler) return;
		for (var i in LinkStyler.presets) {
			var n = LinkStyler.presets[i];
			if (typeof presets.LinkStyler[n] != 'undefined') {
				LinkStyler[n] = presets.LinkStyler[n];
			};
		};
	},

	getType: function(cssClass) {
		if (!cssClass) return null;
		var cssClasses = cssClass.split(/\s+/);
		for (var i = 0; i < cssClasses.length; i++) {
			if (LinkStyler.types[cssClasses[i]]) return LinkStyler.types[cssClasses[i]];
		};
		return null;
	},
	
	overImg: function() {
		this.src = this[(this._realSrc) ? '_realSrc': 'src'].replace(/_l([_.])/, '_h$1');
	},
	
	outImg: function() {
		this.src = this[(this._realSrc) ? '_realSrc': 'src'].replace(/_h([_.])/, '_l$1');
	},

	preloadImgs: [],
	
	initElements: function(elm) {
		if (!document.getElementsByTagName) return;
		var lnks = (elm||document).getElementsByTagName('a');
		if (!lnks) return;
		var ls = LinkStyler;
		
		for (var i=0; i<lnks.length; i++) {
			var lnk = lnks[i];
			// if (!lnk.href) continue;
			var cssClass = lnk.className || '';
			try { // to prevent JS security problems with usr:pwd@xxx links in MSIE 7
				var hrf = lnk.href || '';
			} catch(e) {
				var hrf = '';
			};
			
			if (hrf) {
			
				/* Normalize if necessary ... */
				if (!hrf.match(/^[^:]+:/)) hrf = ls.docPath + hrf;
				hrf = hrf.replace(/\/\.\//g, "/");
				while (hrf.match(/\/\.\.\//)) hrf = hrf.replace(/\/[^\/]+\/\.\.\//, "/");
		
				var base = hrf.replace(/^([^#]*).*/, "$1");
				var prt = hrf.replace(/^([-_a-z0-9]*:).*/, "$1");
				var host = hrf.replace(/^([^:]*:)((\/\/([^\/]*)\/)|[^\/]+).*/, "$4");
				var hsh = hrf.replace(/^([^#]+)(#?.*)/, "$2");
				var ext = hrf.replace(/^[^#?]*(\.[a-zA-Z]+).*/, "$1");
				
				if (navigator.userAgent.match(/rv:(0\.|1\.[0-5][^0-9]).*Gecko\//)) {
					// Fix Mozilla < 1.6 empty replacement bug
					base = base.replace(/^\$1$/, '');
					prt = prt.replace(/^\$1$/, '');
					host = host.replace(/^\$4$/, '');
					hsh = hsh.replace(/^\$2$/, '');
					ext = ext.replace(/^\$1$/, '');
				};
			
			};
			
			/* Make link text breakable ... */
			
			ls.wbr = (!window.opera && document.all) || navigator.userAgent.match('Gecko/')
				? '<wbr />'
				: (
					(navigator.userAgent.match('AppleWebKit/')) 
					? '<span style="letter-spacing: -0.4em;"> </span>'
					: "\u200B"
				);
				
			if (ls.breakableLinks && !lnk.innerHTML.match(ls.wbr) && lnk.firstChild) {
				if (lnk.normalize) lnk.normalize();
				var chld = lnk.firstChild;
				while (chld) {
					if (chld.nodeType == 3) {
						if (ls.wbr == "\u200B") {
							chld.nodeValue = chld.nodeValue.replace(/([-@?&\/])(\S)/g, "$1\u200B$2");
						} else if (chld.splitText) {
							var pos = chld.nodeValue.search(/[-@?&\/]\S/);
							if (pos > -1) {
								chld = lnk.insertBefore(document.createElement('wbr'), chld.splitText(pos + 1));
							};
						};
					};
					chld = chld.nextSibling;
				};
			};
			
			/* Set target according to destination or CSS class ... */
			
			if (!lnk.target) {
				if (ls.getType(cssClass) && ls.getType(cssClass).target)
					lnk.target = ls.getType(cssClass).target
				else if (ext && ls.types[ext] && ls.types[ext].target)
					lnk.target = ls.types[ext].target
				else if (prt && ls.types[prt] && ls.types[prt].target)
					lnk.target = ls.types[prt].target
				else if (host && (host != ls.docHost)) {
					lnk.target = ls.types['external'].target;
				};
			};
			
			/* Set over and out events on link images and preload hover images ... */
			
			if (ls.hoverLinkImages) {
				var lnkimg = (lnk.getElementsByTagName) 
					? lnk.getElementsByTagName('img')
					: ((lnk.all && lnk.all.tags) ? lnk.all.tags('IMG') : null);
				lnkimg = (lnkimg && lnkimg[0]) || null;
				if (lnkimg && lnkimg.src && lnkimg[(lnkimg._realSrc) ? '_realSrc' : 'src'].match(/_l([_.])/) && !lnkimg.onmousover && !lnkimg.onmouseout)
				{
					lnkimg.onmouseover = ls.overImg;
					lnkimg.onmouseout = ls.outImg;
					var src = lnkimg[(lnkimg._realSrc) ? '_realSrc' : 'src'].replace(/_l([_.])/, '_h$1');
					ls.preloadImgs[src] = new Image();
					ls.preloadImgs[src].src = src;
				};
			};
			
			/* Set onclick event handler if provided ... */
			
			if (ls.getType(cssClass) && ls.getType(cssClass).onclick) {
				lnk.onclick = eval(ls.getType(cssClass).onclick);	
			} else if (!cssClass && hrf) {
				/* Check for path fragments ... */
				for (var p in ls.types) {
					if (p.match('/') && hrf.match(p) && ls.types[p].onclick) {
						lnk.onclick = eval(ls.types[p].onclick);
						break;
					};
				};
			};
			
			/* Set CSS classes ... */
			
			if ((!cssClass && ls.autostyleEmptyClass)
			|| (cssClass && cssClass.match(/(^|\s)autostyle(\s|$)/))) {
			
				var trg = (lnk.target) ? lnk.target.toLowerCase() : '';
				var autoClass = '';
				
				if (base == ls.docBase)
					autoClass = 'self'
				else if (ext && ls.types[ext] && ls.types[ext].css)
					autoClass = ls.types[ext].css
				else if (prt && ls.types[prt] && ls.types[prt].css)
					autoClass = ls.types[prt].css
				else
					autoClass = (host != ls.docHost) ? 'external' : 'goto';
				
				cssClass = (cssClass) ? cssClass.replace(/(^|\s)autostyle(\s|$)/, "$1" + autoClass + "$2") : autoClass;
				lnk.className = cssClass;
			};
			
			/* Insert icon placeholder spans ... */
			
			if (document.createElement) {
			
				var cssType = ls.getType(cssClass);
				
				if ((cssType && cssType.iconBefore)
				|| (ext && ls.types[ext] && ls.types[ext].iconBefore)
				|| (prt && ls.types[prt] && ls.types[prt].iconBefore)) {
					if (!lnk._iconBefore && !!(lnk._iconBefore = document.createElement('span'))) {
						lnk._iconBefore.className = 'iconBefore';
						lnk.insertBefore(lnk._iconBefore, lnk.firstChild);
					};
				} else if (lnk._iconBefore) {
					lnk.removeChild(lnk._iconBefore);
					lnk._iconBefore = void(0);
				};
				
				if ((cssType && cssType.iconAfter)
				|| (ext && ls.types[ext] && ls.types[ext].iconAfter)
				|| (prt && ls.types[prt] && ls.types[prt].iconAfter)) {
					if (!lnk._iconAfter && !!(lnk._iconAfter = document.createElement('span'))) {
						lnk._iconAfter.className = 'iconAfter';
						lnk.appendChild(lnk._iconAfter);
					};
				} else if (lnk._iconAfter) {
					lnk.removeChild(lnk._iconAfter);
					lnk._iconAfter = void(0);
				};
				
			};
			
		};
	
	},

	pageLoaded: function() {
		LinkStyler.initElements();
	},
	
	init: function() {
		if (!navigator.userAgent.match) return;
		var ls = LinkStyler;
		ls.getPresets();
		
		ls.docElm = document.documentElement;
		if (ls.docElm) {
			if (!ls.docElm.className) {
				ls.docElm.className = 'linkstylerActive';
			} else if (!ls.docElm.className.match('linkstylerActive')) {
				ls.docElm.className += ' linkstylerActive';
			};
		};
	
		ls.docHref = document.location.href;
		if (navigator.userAgent.match('AppleWebKit/'))
			ls.docHref = ls.docHref.replace(/file:\/([^\/])/, "file:///$1");
		ls.docBase = ls.docHref.replace(/^([^#]*).*/, "$1");
		ls.docPath = ls.docBase.replace(/^(.*\/)[^\/]*$/, "$1");
		ls.docHost = ls.docHref.replace(/^([^:]*:)((\/\/([^\/]*)\/)|[^\/]+).*/, "$4");
		
		/*
		ls.wbr = (!window.opera && document.all) || navigator.userAgent.match('Gecko/')
			? '<wbr />'
			: "\u200B";
		*/
		
		if (window.onDomReady) {
			window.onDomReady(ls.pageLoaded);
		} else if (typeof pageComplete == 'function') {
			ls.oldPageComplete = pageComplete;
			pageComplete = function() {
				ls.oldPageComplete();
				ls.pageLoaded();
			};
		} else {
			ls.oldOnload = window.onload || function(){};
			window.onload = function() {
				ls.oldOnload();
				ls.pageLoaded();
			};
		};

		ls.initComplete = true;
	}

};

if (!LinkStyler.initComplete) LinkStyler.init();




