ようやくできたかも・・・

まだ人柱バージョンですが、たぶん動きます。
概要は、こちらを参照。


にしても、ハテナってフィイルアップロードできないのね。
orz......

// ==UserScript==
// @name           hatebu_switch_a1
// @namespace      http://d.hatena.ne.jp/T-miura/
// @include        http://b.hatena.ne.jp/hotentry*
// @include        http://www.google.co.jp/search*
// ==/UserScript==



/**
 * 概要:
 *
 * 未読、既読の情報によって、
 * 表示する情報を制御するスクリプトです。
 *
 * 前見た情報をもう一度探したい(既読のみを表示)、
 * 既読のリンクは表示して欲しくない
 *
 *
 * といった場合に使用します
 *(ブラウザの履歴使っているだけなのでPC変ると終了ですが)。
 *
 * 現在、対応しているサイトは
 *
 * ・はてブのホットエントリ、
 * ・Googleの検索結果
 *
 * だけですが、PageController.getSite
 * をいじれば簡単に対応サイトを増やせると思います。
 *
 */

	// ログがうざい時に
	var debug =false;
	var logon =false;
	console.debug = console.log;

	if(!logon){
		console.log = function () {};
		if(!debug){
			console.debug = function () {};
		}
	}

//---------------------------------
 
    /**
     * サイト内のリンク
     */
    function  Link(){
    	this.url;
    	this.visited;
    	this.viewNode;
    }



        /**
	 * サイトごとの設定。
	 *
	 *
	 * @return
	 */
	var Site = function () { this.initialize.apply(this, arguments); };
	Site.prototype = {
		initialize: function () {

		this.url;
    	this.judgeXpath
    	this.ViewElmXpath1
    	this.ViewElmXpath2
    	this.visitedColor;

		//CSS変更用のメソッド。
		// changeOn,changeOff,changeAllOffのどれかが入る
    	this.judgeCSSChange;

    	this.links =[];

		},

		//既読を消す。メソッド名微妙
		changeOn: function (linkVisited) {
			return ( linkVisited);
		},
		//未読を消す。メソッド名微妙・・・
		changeOff: function (linkVisited) {
			return (!linkVisited);
		},
		//機能自体を切る。全部表示。メソッド名微妙・・・
		changeAllOff: function (linkVisited) {
			return (false);
		},

		//設定のロード
		load:function(){
			//TODO フラグとかでやったほうがいいかも。
			// こっちのほうがソース簡単で、汎用性高いけど
			var s=  GM_getValue("mode."+this.url);

			if(s !=null){
				this.judgeCSSChange=eval(s );
			}

		},
		//設定のSAVE
		save:function(){

			console.log(this.judgeCSSChange);
			GM_setValue("mode."+this.url,this.judgeCSSChange.toSource());

		},

		/**
		 * 判定対象とするリンクをかき集めます。
		 */
		getLinks:function () {

			var self=this;
			var nodesSnapshot =document.evaluate(self.judgeXpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

			console.log('getLinks:'+self.judgeXpath+'  :size='+nodesSnapshot.snapshotLength);

		    	for ( var i=0 ; i < nodesSnapshot.snapshotLength; i++ )
		    	{
		      		var tmpUrl=nodesSnapshot.snapshotItem(i).textContent;

					if(self.links[tmpUrl] ==null){
		      			self.links[tmpUrl]=new Link();
		      			self.links[tmpUrl].url=tmpUrl;
					}

					console.debug('getLinks:'+tmpUrl+":"+self.links[tmpUrl]);
		    	}

				console.log('getLinks:'+self.links.length);
		},

	       /**
		 * Linkの連想配列を走査し、訪問済みか確認します。
		 */
		checkVisited: function () {
		var self=this;
		console.log( 'checkVisited:'+self.links.length);
		var element = document.createElement('div');
		element.id = 'tempFooter001';
		document.lastChild.appendChild(element);


	    	for ( var i in self.links ) {

				var link = document.createElement("a");
				link.id = "idtempstyle" + i;
				link.href = self.links[i].url;
				link.innerHTML = self.links[i].url;

				document.getElementById('tempFooter001').appendChild(link);
				var color = document.defaultView.getComputedStyle(link,null).getPropertyValue("color");
				document.getElementById('tempFooter001').removeChild(link);

				console.debug( '4:checkVisited:'+color+':');

				if (color == self.visitedColor) {
					self.links[i].visited=true;
				} else {
					self.links[i].visited=false;
				}

			console.debug( '   '+i+":"+self.links[i].url+":"+self.links[i].visited);

	    	}
	    },

		/**
		 * 訪問済みかどうかの情報を使い
		 * viewをいじります。
		 */
		view:function () {
			var self=this;
  			console.log("view:"+self.links.length);

	    	/* Loop through each URL */
	    	for (var i in self.links) {

	    		if( self.links[i].viewNode ==null){

	    			var path=self.ViewElmXpath1 + self.links[i].url +self.ViewElmXpath2;
	    			var nodesSnapshot =document.evaluate( path , document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

	    			this.links[i].viewNode =nodesSnapshot.snapshotItem(0);

					if(! this.links[i].viewNode){
						console.log("can't get ViewNode:"+self.links[i].url);
						continue;
					}
	    		}

				console.debug("view:"+self.links[i].url+":"+self.links[i].visited);

	    		/* 訪問したことのある要素の状態を変更します。 */
	    		if ( self.judgeCSSChange ( self.links[i].visited ) ){ // visited

	    			console.debug( 'change css none:' +self.links[i].url);
	    			self.links[i].viewNode.style.display='none';


	    		}else{

	    			console.debug( 'change css display:' +self.links[i].url);
	    			console.debug( 'nodesSnapshot:' + self.links[i].viewNode);

					self.links[i].viewNode.style.display='';
	    		}


	    	}
	    },
	}

// ------------------------------------------------------------------

	/**
	 * 基点となるクラス。
	 * UI部分を提供。
	 *
	 * PageController > Site > Link
	 *
	 * という形で処理を委譲
	 *
	 *
	 */
	var PageController = function () { this.initialize.apply(this, arguments); };
	PageController.prototype = {
		initialize: function () {

		this.opened = false;
		this.container = null;
		this.closeTimer = null;

		this.update();

		this.site = this.getSite();

		// getLinks,checkVisited,viewは今は
		// セットのように扱っているけど、
		// 前は、呼び出すタイミングを分けていた。

		this.site.getLinks() ;
		this.site.checkVisited() ;
		this.site.load();
		this.site.view();

		this.registReloadEvent();

		},

	    // サイト(はてぶ、Google等)の解析のために必要なデータを持つクラス
		// このコントローラで制御対象のサイトを取得する
	    getSite: function  (){
			var sites =new Array(1);

			// ハテブ用定義
			var site1 = new Site();
			// まず、対象とするサイト
		    site1.url='http://b.hatena.ne.jp/hotentry';
			// 既読、未読を判定したいURL
			site1.judgeXpath='//div[@class="entry-body"]/h3/a/@href'
			// 上記URLを表示しているDIV、ブロック
			// この単位で表示をいじる。
			// なお、上記のURLでパスは引っ掛ける
			site1.ViewElmXpath1='//div[@class="entry-body"]/h3/a[@href=\''
			// こっちは、URL後の部分のXPATH
			site1.ViewElmXpath2='\']/../../..';
			// サイトによって既読のカラーが違うっぽいので持つことに
			// CSSからひっぱてきたほうがいいのか・・・?
		    	site1.visitedColor='rgb(136, 51, 136)';
			//デフォルトのモード
		    site1.judgeCSSChange =site1.changeOn;

			sites[0]=site1;

			// Google用
			var site2 = new Site();
		    	site2.url='http://www.google.co.jp/search';
			site2.judgeXpath='//a[@class="l"]/@href'
			site2.ViewElmXpath1='//li[@class="g"]/h3/a[@href=\''
			site2.ViewElmXpath2='\']/../..';
		    site2.visitedColor='rgb(85, 26, 139)';
		    site2.judgeCSSChange =site1.changeOn;

			sites[1]=site2;

			// マッチするサイトを返す
			for(var i=0 ; i < sites.length; i++ ){
				var b =location.href.match(sites[i].url );
				if(b){
					console.log('getSite!!'+sites[i].url);

					sites[i].load();
					return(sites[i] );
				}else{
					console.log('nonSite!!'+sites[i].url);
				}
			}
			return(null);

	    },

		open: function () {
			if (this.container) {
				this.opened = true;
				this.container.className = "playlist-controller";
			}
		},
		close: function () {
			if (this.container) {
				this.opened = false;
				this.container.className = "playlist-controller closed";
			}
		},
		registReloadEvent: function () {

			console.log("registReloadEvent ");
            var self= this;

		   document.addEventListener('DOMNodeInserted',
          	function (evt) {

				//オートページャ用にイベントをみるつもりだったが、
				//かなりやばい動きをする場合があるので中止。
				//表示カットによって、連続で10ページ
				//オートページャ でロードされたりする。

				//self.site.getLinks() ;
				//self.site.checkVisited() ;

			},
          false);






		},


		cancelClosing: function () {
			if (this.closeTimer) {
				clearTimeout(this.closeTimer);
				this.closeTimer = null;
			}
		},
		closeLater: function (msec) {
			var self = this;
			this.cancelClosing();
			this.closeTimer = setTimeout(function () {
				self.closeTimer = null;
				self.close();
			}, msec || 300);
		},





		update: function () {
			var self = this;
			var listScrollTop = 0;

			var box = document.getElementById("pageController" );
			if (!box) {
				box = document.createElement("div");
				box.id = "pageController" ;
				box.className = "playlist-controller" + (this.opened ? "" : " closed");

				Util.observe(box, "mousemove", function (ev) {
					if (!self.opened) {
						self.open();
					} else {
						self.cancelClosing();
					}
				});
				Util.observe(box, "mouseout", function (ev) {
					if (!self.opened || self.pinned) return;
					if (box != ev.target && box != ev.srcElement) return;
					self.closeLater();
				});
				document.body.appendChild(box);
			} else {
				var lists = box.getElementsByTagName("ul");
				for (var i = 0, len = lists.length; i < len; i++) {
					var ul = lists[i];
					if (ul && /\bplaylist-list-inner\b/.test(ul.className)) {
						listScrollTop = ul.scrollTop;
						break;
					}
				}
				box.innerHTML = "";
			}
			this.container = box;
/**
			var header = document.createElement("div");
			header.className = "playlist-header";
			box.appendChild(header);

			this.__addLinkButton(header, {
				caption: "×",
				title: "プレイリストを閉じる",
				className: "playlist-window-button playlist-window-button-close",
				click: function () { self.close(); }
			});


			var title = document.createElement("p");
			title.className = "playlist-title";
			header.appendChild(title);
*/
			var buttons = document.createElement("div");
			buttons.className = "playlist-buttons";
			box.appendChild(buttons);


			this.__addButton(buttons, {
					caption: "visited On",
					className: "playlist-button-add-this-video",
					click: function () {


					self.site.judgeCSSChange = self.site.changeOn;
					self.site.save();

					//この呼び出し方はまた組みなおす
					//つもりなので、メソッド化していない。
					self.site.getLinks( );
					self.site.checkVisited( );
					self.site.view( );

					}
				});

			this.__addButton(buttons, {
				caption: "visited Off",
				className: "playlist-button-add-videos-in-page",
				click: function () {

					self.site.judgeCSSChange = self.site.changeOff;
					self.site.save();

					self.site.getLinks( );
					self.site.checkVisited( );
					self.site.view( );

				}
			});
			this.__addButton(buttons, {
				caption: "OFF",
				className: "playlist-button-play",
				click: function () {

					self.site.judgeCSSChange = self.site.changeAllOff;
					self.site.save();

					self.site.getLinks( );
					self.site.checkVisited( );
					self.site.view( );
				},

			});



		},

		__addLinkButton: function (parent, def) {
			var btn = document.createElement("a");
			btn.href = "javascript:void(0);";
			btn.innerHTML = def.caption;
			btn.className = "playlist-link-button";
			if (def.id) btn.id = def.id;
			if (def.className) btn.className += " " + def.className;
			if (def.title) btn.title = def.title;
			if (def.click) Util.observe(btn, "click", (function (b, f) {
				return function () { f.apply(b, arguments); };
			})(btn, def.click));
			parent.appendChild(btn);
		},
		__addButton: function (parent, def) {
			var btn = document.createElement("input");
			btn.type = "button";
			btn.value = def.caption;
			btn.className = "submit playlist-button";
			if (def.id) btn.id = def.id;
			if (def.className) btn.className += " " + def.className;
			if (def.disabled) btn.disabled = true;
			if (def.click) Util.observe(btn, "click", (function (b, f) {
				return function () { f.apply(b, arguments); };
			})(btn, def.click));
			parent.appendChild(btn);
		},

	};


	var Util = {
			observe: function (elem, event, func, capture) {
				if (elem.attachEvent) {
					elem.attachEvent("on" + event, func);
				} else if (elem.addEventListener) {
					elem.addEventListener(event, func, !!capture);
				} else {
					elem["on" + event] = func;
				}
			},
			stopObserving: function (elem, event, func, capture) {
				if (elem.detachEvent) {
					elem.detachEvent("on" + event, func);
				} else if (elem.removeEventListener) {
					elem.removeEventListener(event, func, !!capture);
				} else {
					delete elem["on" + event];
				}
			}
		};

	//余計なスタイルはいってるけど、そこはスルーで
	GM_addStyle(<><![CDATA[
         	.playlist-controller {
      			position: fixed;
      			width: 400px;
      			left: 0px;
      			top: 30px;
      			border: 1px solid #CCC;
      			background-color: #FFF;
      			overflow: hidden;
      		}
      		.playlist-controller.closed {
			position: fixed;
      			left: -395px;
      		}

      		.playlist-header {
      			margin: 5px;
      			padding: 2px 5px;
      			border-bottom: 1px solid #333;
      		}
      		.playlist-title {
      			font-size: 90%;
      			font-weight: bold;
      		}
      		a.playlist-window-button {
      			float: right;
      			display: block;
      			width: 16px;
      			height: 16px;
      			font-size: 12px;
      			font-family: monospace;
      			font-weight: bold;
      			line-height: 16px;
      			text-align: center;
      			text-decoration: none;
      			border-width: 1px;
      			border-style: solid;
      			border-color: #CCC #999 #999 #CCC;
      			margin-right: 2px;
      			outline: none;
      		}
      		a.playlist-window-button-pin.pinned {
      			border-color: #999 #CCC #CCC #999;
      			background-color: #AAA;
      		}

      		.playlist-buttons {
      			margin: 10px;
      			position: relative;
      		}
      		.playlist-buttons:after {
      			content: ".";
      			clear: both;
      			display: block;
      			height: 0;
      			visibility: hidden;
      		}
      		.playlist-button {
      			margin-right: 5px;
      			float: left;
      		}
      		.playlist-button-clear {
      			float: right;
      		}

      		.playlist-list-outer {
      			margin: 0 10px;
      			padding: 0;
      			border: 1px solid #999;
      			height: 205px;
      		}

      		.playlist-list-inner {
      			list-style-type: none;
      			margin: 0;
      			padding: 0;
      			width: 100%;
      			height: 100%;
      			overflow: auto;
      		}

      		.playlist-list-item {
      			white-space: nowrap;
      		}
      		.playlist-list-item.even {
      			background-color: #EEE;
      		}

      		a.playlist-list-item-title {
      			display: block;
      			padding: 2px 5px;
      			overflow: hidden;
      			outline: none;
      		}
      		a.playlist-list-item-button {
      			font-size: 12px;
      			font-family: monospace;
      			font-weight: bold;
      			text-decoration: none;
      			padding: 2px 5px;
      			float: right;
      			outline: none;
      		}
      		a.playlist-list-item-button-del {
      			color: #D00;
      		}

      		.playlist-footer {
      			margin: 5px 10px;
      			text-align: right;
      		}
      		.playlist-footer:after {
      			content: ".";
      			clear: both;
      			display: block;
      			height: 0;
      			visibility: hidden;
      		}

      		.playlist-mode-selector {
      			float: left;
      		}
      		a.playlist-mode-finish {
      			float: left;
      			font-size: 12px;
      			text-decoration: none;
      			padding: 0 5px;
      			border-width: 1px;
      			border-style: solid;
      			border-color: #CCC #999 #999 #CCC;
      			outline: none;
      			margin-left: 5px;
      		}

      		.playlist-checkbox {
      			margin-left: 10px;
      			vertical-align: middle;
      		}
      		.playlist-checkbox-label {
      			vertical-align: middle;
      		}
      	]]></>);
// ------------------------------------------------------------------

console.log( 'load: my script');

new PageController();
		  	          	

う〜ん。微妙にレイアウト崩れる。