// ==UserScript==
// @name         CSS Linkify
// @namespace    http://www.akatsukinishisu.net/
// @description  convert URLs in CSS to link anchor.
// @include      *.css
// ==/UserScript==

// Version: 2006-02-06

(function(){
	var d = document;

	/* CSS content is treated as PRE element. */
	var nPre = d.getElementsByTagName('PRE')[0];

	/* take CSS text */
	var cssStr = getInnerTextAndRemove(nPre);

	/* @import "..." -> @import iurl(...) */
	while ( cssStr.match(/(@import\s+)(["'])([^\2\s]+)(\2)/) ) {
		cssStr = RegExp.leftContext
			+ RegExp.$1 + 'iurl('
			+ RegExp.$2 + RegExp.$3 + RegExp.$2
			+ ')' + RegExp.rightContext;
	}

	/* divide into the URL part and other text parts. */
	var urls = new Array();
	var texts = new Array();
	while ( cssStr.match(/(i?url\(\s*)([^)\s]+)(\s*\))/i ) ){
		urls[urls.length] = RegExp.$2;
		var t = RegExp.leftContext;
		cssStr = RegExp.rightContext;
		/*  not include "iurl(", ")" */
		if ( RegExp.$1 != 'iurl(' ) {
			t += RegExp.$1;
			cssStr = RegExp.$3 + cssStr;
		}
		texts[texts.length] = d.createTextNode(t);
	}
	texts[texts.length] = d.createTextNode(cssStr);

	/* convert URL part into A element node. */
	for (var j = urls.length - 1; j >= 0; j--) {
		var frag = d.createDocumentFragment();
		var quote = '';
		if ( urls[j].match(/^(["']).+\1$/) ) {
			urls[j] = urls[j].substr(1, urls[j].length - 2);
			quote = RegExp.$1;
		}
		var nA = d.createElement('A');
		nA.href = urls[j];
		nA.appendChild(d.createTextNode(urls[j]));
		quote && frag.appendChild(d.createTextNode(quote));
		frag.appendChild(nA);
		quote && frag.appendChild(d.createTextNode(quote));
		urls[j] = frag;
	}

	/* return CSS text node and a element node to pre element */
	while (texts.length || urls.length) {
		texts.length && nPre.appendChild(texts.shift());
		urls.length && nPre.appendChild(urls.shift());
	}

	/* acquire internal text and delete child node */
	function getInnerTextAndRemove(n) {
		var result = '';
		while (n.firstChild) {
			var child = n.firstChild;
			if (child.nodeType == 1) {
				result += getInnerTextAndRemove(child);
			} else if (child.nodeType == 3) {
				result += child.nodeValue;
			}
			n.removeChild(child);
		}
		return result;
	}
})();

