IncrementalFilter4GoogleSearch

By jimo1001 Last update Aug 1, 2009 — Installed 5,325 times.

There are 8 previous versions of this script.

// ==UserScript==
// @name           IncrementalFilter4GoogleSearch
// @namespace      jimo1001
// @include        http://www.google.co.jp/search*
// @version        0.92
// ==/UserScript==

(function() {
	// Class: Paragraph
	var Paragraph = function(node) {
		this.node = node;
		this.hidden = false;
		this.content = node.textContent;
	};
	Paragraph.prototype.hide = function() {
		this.node.style.display = "none";
		this.hidden = true;
	};
	Paragraph.prototype.show = function() {
		this.node.style.display = "";
		this.hidden = false;
	};
	// Class: ParagraphManager
	var ParagraphManager = function(nodes) {
		this.pool = [];
		this.cacheContexts = [];
		this.timeoutID = null;
		this.intervalID = null;
		this.createInstance(nodes);
		this.elm = this.createInputElement();
		this.setEvent(this.elm);
	};
	ParagraphManager.prototype.getContext = function() {
		return this.elm.input.value || "";
	};
	ParagraphManager.prototype.createInstance = function(nodes) {
		var self = this;
		nodes.forEach(function(node) {
			self.pool.push(new Paragraph(node));
		});
	};
	ParagraphManager.prototype.filterParagraphs = function(str) {
		var paragraphs = [], contexts = [];
		var f = this.checkFilterContext(str);
		if(f.init) {
			paragraphs = this.pool;
			contexts = this.cacheContexts;
		} else {
			paragraphs = this.pool.filter(function(elm) { return !elm.hidden });
			contexts = f.contexts;
		}
//		console.log("init: ", f.init, ", contexts: ", contexts, "f.contexts: ", f.contexts, ", cacheContexts: ", this.cacheContexts);
		this.filter(contexts, paragraphs);
	};
	ParagraphManager.prototype.filter = function(contexts, paragraphs) {
		if(!contexts.length) return;
		paragraphs.forEach(function(paragraph) {
			var match = true;
			contexts.forEach(function(context) {
				if(!paragraph.content.match(new RegExp(context, "i"))) match = false;
			});
			(match) ? paragraph.show() : paragraph.hide();
		});
	};
	ParagraphManager.prototype.checkFilterContext = function(str) {
		var self = this, initFilter = false;
		var currentContexts = str || this.getContext(), samedContexts = new Array(this.cacheContexts.length);
		var addedContexts = currentContexts.split(" ").filter(function(current,i) {
			var samedContext = self.cacheContexts.some(function(cache, j) {
				var sameContext = (current == cache);
				if(sameContext) samedContexts[j] = true;
				return sameContext;
			});
			return !samedContext;
		});
		for(var i = 0, num=0; i < samedContexts.length; i++) {
			if(!samedContexts[i]) self.cacheContexts.splice(i-num++, 1);
			if((i+1)==samedContexts.length && num != 0) initFilter = true;
		}
		this.cacheContexts = this.cacheContexts.concat(addedContexts);
		if(addedContexts=="") initFilter = true;
		return {"contexts": addedContexts, "init": initFilter};
	};
	ParagraphManager.prototype.createInputElement = function() {
		var css = "div#IF4G_indicator { height: 2px; background: green; width: 0; margin-top: 2px; }";
		addStyle(css);
		var input = $X("id('sff')//td/input[@type='text']")[0];
		var indicator = document.createElement("div");
		indicator.setAttribute("id", "IF4G_indicator");
		input.parentNode.appendChild(indicator);
		return {"input": input, "indicator":indicator};
	};
	ParagraphManager.prototype.setEvent = function(elm) {
		var self = this;
		var setOpacity = function(num) {
			elm.input.parentNode.setAttribute("style","opacity:"+num);
		}
		elm.input.addEventListener("keyup", function() {
			if(self.timeoutID) {
				window.clearTimeout(self.timeoutID);
				clearInterval(self.intervalID);
			}
			var width = 0;
			self.intervalID = window.setInterval(function(){
				width += 25;
				elm.indicator.style.width = (width + "%");
			}, 200);
			self.timeoutID = window.setTimeout(function() {
				self.filterParagraphs(elm.input.value);
				clearInterval(self.intervalID);
			}, 800);
		}, false);
	};

	var addStyle = function(css) {
		var link = document.createElement('link');
		link.rel = 'stylesheet';
		link.href = 'data:text/css,' + escape(css);
		document.documentElement.childNodes[0].appendChild(link);
	};

	if(document.body) {
		var xpath = ".//li[contains(concat(' ',@class,' '),'g')]";
		var pm = new ParagraphManager($X(xpath));
		var boot = function() {
			window.AutoPagerize.addFilter(function(docs) {
				pm.createInstance($X(xpath, docs[0]));
				pm.filterParagraphs();
			});
		};
		if(window.AutoPagerize) {
			boot();
		}else{
			window.addEventListener('GM_AutoPagerizeLoaded', boot, false);
		};
	};
	//=== extend version of $X ===
	// http://coderepos.org/share/browser/lang/javascript/userscripts/jautopagerize.user.js?rev=1966
	function $X (exp, context, type /* want type */) {
		if (arguments.callee.forceRelative || navigator.userAgent.indexOf("Safari/523.12") != -1)
			exp = exp.replace(/id\(\s*([\"\'])([^\"\']+)\1\s*\)/g, '//*[@id="$2"]');
		if (arguments.callee.forceRelative)
			exp = exp.indexOf("(//") == 0
			? "(.//" + exp.substring(3)
			: (exp[0] == "/" ? "." : "./") + exp;
		if (typeof context == "function") {
			type = context;
			context = null;
		}
		if (!context) context = document;
		exp = (context.ownerDocument || context).createExpression(exp, function (prefix) {
			return document.createNSResolver((context.ownerDocument == null ? context
											  : context.ownerDocument).documentElement)
				.lookupNamespaceURI(prefix) || document.documentElement.namespaceURI;
		});
		switch (type) {
		case String:
			return exp.evaluate(context, XPathResult.STRING_TYPE, null).stringValue;
		case Number:
			return exp.evaluate(context, XPathResult.NUMBER_TYPE, null).numberValue;
		case Boolean:
			return exp.evaluate(context, XPathResult.BOOLEAN_TYPE, null).booleanValue;
		case Array:
			var result = exp.evaluate(context, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
			var ret = [];
			for (var i = 0, len = result.snapshotLength; i < len; i++) {
				ret.push(result.snapshotItem(i));
			}
			return ret;
		case undefined:
			var result = exp.evaluate(context, XPathResult.ANY_TYPE, null);
			switch (result.resultType) {
			case XPathResult.STRING_TYPE : return result.stringValue;
			case XPathResult.NUMBER_TYPE : return result.numberValue;
			case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
			case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: {
				/* not ensure the order. */
				var ret = [];
				var i = null;
				while (i = result.iterateNext()) {
					ret.push(i);
				}
				return ret;
			}
			}
			return null;
		default:
			throw(TypeError("$X: specified type is not valid type."));
		}
	}
})();