編集画面のオートセーブ機能について

この機能は、localStrage関数を応用して実現しています。localStrageなどといったWebStrageとは、W3C Working Draft 10 September 2009で定義されているデータをブラウザ側に蓄積する仕組みです。よく、ローカルにデーターを保存する手段としてCookieを思い浮かべますが、その都度リクエストする必要が無い点と、大容量のデーター(規格上5M)をやり取りできるというところが異なります。

Web Strageは原則的に多言配列をそのまま保存できるものではないため、JavaScript1.8.5で定義されているJSON関数を用いて配列化、テキストストリング化を行ないます。この関数は、まだネイティブサポートしているブラウザが少ないので、実装にhttp://www.json.org/json2.jsを使用します。WebStrageに保存する場合は、setItemを使用します。

// localStorageに保存
var foo = {bar:0, hoge: 32, ...};	// この変数をそのままWeb Storageに保存することはできない。
var str = JSON.stringify(foo);	// JSON.stringfyでひとつのテキストストリングにする。
window.localStorage.setItem('foo_data',str);	// localStorageに保存

呼び出すときは逆手順で、getItemを使用し、JSON.parseで配列化します。

// localStorageから読み込み
var storage = window.localStorage.getItem('foo_data');	// localStorageから、データーを取得
var data = JSON.parse(storage);			// 配列に戻す
console.log(data)

これで読み書きが実装されました。Cookieより簡単ですねぇ。データーを削除するときは以下のようにします。

window.localStorage.removeItem('foo_data');

使用できるブラウザは、IE8以上、FireFox3.1以上、 Webkit 3.1.2相当以上、Opera9.62以上で、この記事を書いている現時点のブラウザではすべてサポートしています。

PukiWiki Adv.の実装

PukiWiki Adv.ではあくまでも編集画面を自動保存するという目的で使用しています。例えば、間違えてウィンドウを閉じたり、ブラウザがクラッシュしてデーターがお釈迦になってしまう時の対策です。localStorageが使用できるかの判定は、Modernizr.localstorageで行います。

保存するデーターは、localStorageの参照名は、ページ名とし、テキストデーターの他に、テキストエリアの最終保存日時を保存します。この最終保存日時は、ページの更新判定で使用します。例えば、ページの最終保存日時がlocalStorageに保存されている保存日時よりも新しい場合、更新があったと判断できます。ただし、この判定処理だけでは、「タイムスタンプを更新しない」のチェックをした場合の判断ができません。そこで、保存されているデーターと、サーバー上のデーターが一致するかも確認します。(せいぜい、表示されるメッセージが変わるくらいの処理でしかありませんが・・・)

データーの更新は、onkeypressイベント毎です。つまり、キー入力された時点のタイミングで更新されます。(果たしてこの実装でいいのか疑問ですが)

$(prefix+'.edit_form textarea[name=msg]').keypress(function(){
	// テキストエリアの内容をlocalStrageにページ名と共に保存
	if (Modernizr.localstorage){
		var d=new Date();
		window.localStorage.setItem(PAGE,JSON.stringify({
			msg : $(this).val(),
			modified: d.getTime()
		}));
	}
});

読み込み時の処理:

// テキストエリアの内容をlocalStrageから取得
if (Modernizr.localstorage){
	var msg = $(prefix+'.edit_form textarea[name=msg]').val();
	var storage = window.localStorage.getItem(PAGE);
	var data = JSON.parse(storage);

	if (data){
		// 「タイムスタンプを更新しない」で更新した場合、それを検知する方法がないという致命的問題あり。
		var ask = (MODIFIED > data.modified && data.msg !== msg) ?
			'過去に編集したデーターよりもページが新しいようです。復元しますか?' :
			'過去に編集したデーターがあるようです。復元しますか?';

		// データーを復元
		if (confirm(ask)){ $(prefix+'.edit_form textarea[name=msg]').val(data.msg); }
	}
}

localStorageのデーター削除するタイミングは、更新した時と、キャンセルボタンが押された時です。ただ、現時点の実装では、「サーバーに保存された」という確認ができていないので、まだ不十分と言えますね。

// 送信が押された時の処理
$(prefix+'form').submit(function(){
	// localStrageをフラッシュ(キャンセルボタンを押した場合も)
	if (Modernizr.localstorage){
		localStorage.removeItem(PAGE);
	}
});

ちなみに、tDiaryでは下書きとして保存するという目的で使われています。