l'essentiel est invisible pour les yeux

Sunday, November 05, 2006

[javascript] IEとFirefox2.0以上で動作するClient Side Storage

Firefox2.0では、WHATWGのWeb Application1.0仕様の一部である、Client Side Storageを実装しています。FirefoxのClient Side Storageには、セッション中のみデータが有効で同一ドメイン間のみアクセスできるSession Storageと永続データ管理が可能でクロスドメインでデータにアクセスすることもできるGlobal Storageがあります。

これにより、IE5以上とFirefox2.0以上で永続データ管理が可能になりました。どうせなら同じAPIで使用したいのでFacadeデザインパターンを使用し、カプセル化したいと思います。

Client Side Storageデモ


その前に、Firefox2.0sessionStorageとglobalStorageについて。

sessionStorage
sessionStorageはセッションが切れるとデータも削除されます。また同じドメイン間でしか同じストレージにアクセスすることは出来ない。
Web Application1.0仕様そのままですが。
同一サイトの複数のウインド間でチェックボックスの値を共有することができる。


<label>
input type="checkbox" onchange="sessionStorage.insurance = checked">
I want insurance on this trip.
</label>
if (sessionStorage.insurance) { ... }


今回使用したのは、globalStorage.

globalStorage
globalStorageはセッションをまたがって永続的にデータを格納することが出来ます。データの保存方法によっては、クロスドメインからアクセスすることもできるのでセキュリティ上注意が必要です。

  • globalStorage[''] は全てのドメインからアクセス可能
  • globalStorage['com'] は.comドメインならアクセス可能
  • globalStorage['example.com'] は.example.comドメインならアクセス可能
  • globalStorage['www.example.com'] はwww.example.comとexample.comからアクセス可能


IE5以上に実装されている、UserData BehaviourとglobalStorageを共通のAPIで使えるようなクラスを書いてみた。

Client Side Storageデモ
複数のウインドを開いて片一方のウインドでTEXTAREA内を編集し保存→もう一方で復帰すると保存したデータが表示される。もちろんブラウザを閉じてもデータは有効。
// UserAgent
var UA = navigator.userAgent.toLowerCase();
var isIE = ((UA.indexOf('msie') != -1) && (UA.indexOf('opera') == -1))? true : false;
var isGecko = (UA.indexOf('gecko') != -1)? true : false;

// Client Side Storage Facade pattern
var ClientSideStorage = Class.create();
ClientSideStorage.prototype = {
_storage: null,
_sStoreName: 'ClientSideStorage',
initialize: function(options) {
options = options || {};
this._namespace = options.namespace || ((location.port == "")? location.host :
location.host.substr(0, location.host.length - location.port.length - 1)); // ポート番号を取り除く
this._expires = options.expires || new Date(2085, 3, 12);
if(isGecko && globalStorage) this._storage = globalStorage[this._namespace];
else if(isIE){
this._storage = document.createElement('div');
this._storage.style.behavior = "url(#default#userData)";
this._storage.expires = this._expires.toUTCString();
(document.getElementsByTagName('body')[0] || document.documentElement).appendChild(this._storage);
this._ie = true;
} else {
throw "Client side storage is supported at only since IE 5.0 and Firefox 2.0";
}
},
setItem: function(key, value) {
if(!this._ie) this._storage[key] = value;
else {
this._storage.setAttribute(key.camelize(), value);
this._storage.save(this._sStoreName);
}
},
getItem: function(key) {
if(!this._ie) return this._storage[key];
else {
this._storage.load(this._sStoreName);
return this._storage.getAttribute(key.camelize());
}
},
removeItem: function(key) {
if(!this._ie) this._storage.removeItem(key.camelize());
else {
this._storage.load(this._sStoreName);
this._storage.setAttribute(key.camelize(), '');
}
}
}

で使ってみる。

var storage = new ClientSideStorage;
storage.setItem('data', 'えいぞくでーた');
console.log(storage.getItem('data')); // => "えいぞくデータ"
storage.removeItem('data'); // => 削除
console.log(storage.getItem('data')); // => undefined

動いた。

一点気をつける必要があるのは、globalStorage['domain']に与えるドメイン名にポート番号を含んでいるとSecurity Errorが発生するのでポート番号は取り除いている。

参考
Firefox, JavaScript and the Web
5.3. [SCS] Client-side session and persistent storage
[MSDN] Introduction to Persistence