// find in page:
(function () {
	var q = window.prompt('Find (leave blank to clear):', ''), // find text
		d = document,
		id = d.__findId, // id (class actually) to identify our spans
		es, // list of elements
		esl, // length of list of elements
		e, // element
		ns, // list of nodes
		nsl, // length of list of nodes,
		n, // node
		re, // regular expression built from find text
		l, // find text length
		s, // span element template
		m, // number of matches
		f, // document fragment for multiple node insertions
		v, // original text value
		t, // text value for searching (&nbsp; replaced with regular space)
		p, // position of match in text value
		w, // first span to scroll to
		i, j, k; // loop counters

	if (q == null) { // do nothing if user tapped cancel
		return;
	}

	if (id) { // clear previous find results
		es = d.getElementsByTagName('span');
		for (i = es.length - 1; i >= 0; i--) {
			s = es[i];

			// handle only our spans
			if (s.__findId != id) {
				continue;
			}

			e = s.parentNode;
			n = s.firstChild;
			j = s.previousSibling;
			k = s.nextSibling;

			e.replaceChild(n, s);

			// merge with adjacent text nodes
			if (j && j.nodeType == 3) {
				j.nodeValue += n.nodeValue;
				e.removeChild(n);
				n = j;
			}
			if (k && k.nodeType == 3) {
				n.nodeValue += k.nodeValue;
				e.removeChild(k);
			}
		}
	}

	if (!q) { // only clear results if user didn't enter anything
		return;
	}

	if (!id) { // generate find id
		d.__findId = id = 'find' + (new Date()).getTime();
	}

	re = new RegExp(q.replace(/([\\^$*+?.|(){}\[\]])/g, '\\$1'), 'i');
	l = q.length;

	// build span template
	s = d.createElement('span');
	s.style.color = 'black';
	s.style.backgroundColor = '#ffff99';
	s.style.fontWeight = 'bold';

	m = 0;

	// build list of elements to check
	i = d.getElementsByTagName('body')[0];
	es = [].slice.call(i.getElementsByTagName('*'), 0);
	es.unshift(i);
	esl = es.length;

	for (i = 0; i < esl; i++) {
		e = es[i];
		ns = e.childNodes;
		nsl = ns.length;
		for (j = 0; j < nsl; j++) {
			n = ns[j];

			// search only text nodes
			if (n.nodeType != 3) {
				continue;
			}

			f = d.createDocumentFragment();
			v = n.nodeValue;
			t = v.replace(/\u00A0/g, ' ');

			// split text node into multiple text nodes and spans
			while ((p = t.search(re)) > -1) {
				f.appendChild(d.createTextNode(v.substring(0, p)));
				k = s.cloneNode(false);
				k.__findId = id;
				k.appendChild(d.createTextNode(v.substring(p, p + l)));
				f.appendChild(k);
				if (!w) {
					w = k;
				}
				v = v.substring(p + l);
				t = t.substring(p + l);
				m++;
			}

			e.insertBefore(f, n);

			if (v.length > 0) {
				n.nodeValue = v;
			} else {
				e.removeChild(n);
			}
		}
	}

	if (w && w.scrollIntoView) {
		w.scrollIntoView();
	}
	alert('Found ' + m + ((m == 1) ? ' match' : ' matches'));
})()
