ページのスクロール位置を自動で保存/復元するgreasemonkeyスクリプト

俺がタブを数百枚とか、時にfirefoxが1.5GBにも達するほど開くのはタブを閉じると以前のスクロール位置が失われるからで、要するにどこまで読んだかを保存しておきたかった。


grasemonekey+gearsでやってみよう、と今日の午後に始めたが、
http://code.google.com/intl/ja/apis/gears/articles/gearsmonkey.html

// Correct gears init code
var server = null;
var store = null;
function initGears() {
if (!unsafeWindow.google) unsafeWindow.google= {};
if (!unsafeWindow.google.gears){
  unsafeWindow.google.gears= {factory: new GearsFactory()};
  try {
    server = unsafeWindow.google.gears.factory.create('beta.localserver', '1.0');
    store = server.createStore("wikipedia_offline");
  } catch(e) {}
}

は現在のところ動かない。ブラウザが落ちる…

Now our code looks like this:

ぐぐる先生! 今のコード教えてください!




しようがないのでGM_setValue/GM_getValueで作った。
なんだかデータベースが汚れそうな気がしたので連想配列を文字列化して保存するようにした。使ってるのはロック1、データ1なので消すときは楽。数百程度ではパフォーマンスが落ちたりはしないはず。どこまで保存できるかは試していない。


スクロール位置を取得して戻してるだけなので、この手の手法の限界として、ウィンドウサイズが変更されると位置がズレる。


googleでこの機能を使う人はいないと思うので、試される方は@includeとスクリプト中のpathを適当に書き換えることを推奨しときます。


修正履歴

// ==UserScript==
// @name           restore_y
// @namespace      http://d.hatena.ne.jp/ruby-U
// @description    auto save and restore page y-position.
// @include        http://www.google.co.jp/*
// ==/UserScript==

//settings
var path = '^/search';// target pathname pattern.


var mainid = location.hostname + path;
var dataid = mainid + '//data';

function getDataHash(){
	return eval(GM_getValue(dataid, {}));
}
function setDataHash(hash){
	var arr = [], i = -1;
	for(var key in hash){
		var value = hash[key];
		arr[++i] = '"' + key + '":' + ('number' == typeof(value)? value: '"' + value + '"');
	}
	var str = "({" + arr.join(',') + "})";
	GM_setValue(dataid, str);
}
function transactionSave(key, value){
	function save(key, value){
		var hash = getDataHash();
		hash[key] = value;
		setDataHash(hash);
	}
	var success = false;
	for(var i = 0; i < 5; i++){
		if( !GM_getValue(mainid, false) ){
			GM_setValue(mainid, true);
			save(key, value);
			GM_setValue(mainid, false);
			success = true;
			break;
		}
	}
	if(!success){
		//when timeout
		save(key, value);
	}
}

var y      = null;
if( !path || ( path && location.pathname.match(new RegExp(path)) ) ){
	window.addEventListener("load",
		function(){
			//restore
			var _y = getDataHash()[location.href];
			if(void 0 !== _y){
				y = _y;
				var x = document.body.scrollLeft || document.documentElement.scrollLeft;
				window.scrollTo(x, y);
			}
		}, true);
	window.addEventListener("scroll",
		function(){
			//capture
			y = document.body.scrollTop  || document.documentElement.scrollTop;
		}, true);
	window.addEventListener("unload",
		function(){
			//save
			transactionSave(location.href, y);
		}, true);
}

if (void 0 !== typeof GM_registerMenuCommand) {
    GM_registerMenuCommand('restore_y stored data infomation', function() { 
    	var hash = getDataHash();
    	var count = 0;
    	for(var key in hash){
    		count++;
    	}
    	alert(
    		'total records: ' + count + '\n'+
    		'y: ' + hash[location.href]
    	);
    });
}