<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Web Storage &#8211; Mach3.laBlog</title>
	<atom:link href="https://blog.mach3.jp/tag/web-storage/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.mach3.jp</link>
	<description></description>
	<lastBuildDate>Fri, 20 Dec 2013 01:39:00 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>
	<item>
		<title>&#034;userData&#034; &#8211; Alphabetical Advent Calendar 2013</title>
		<link>https://blog.mach3.jp/2013/12/20/jaac2013-u-userdata.html</link>
		
		<dc:creator><![CDATA[mach3]]></dc:creator>
		<pubDate>Fri, 20 Dec 2013 01:39:00 +0000</pubDate>
				<category><![CDATA[Laboratory]]></category>
		<category><![CDATA[Advent Calendar 2013]]></category>
		<category><![CDATA[Internet Exploer]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[userData]]></category>
		<category><![CDATA[Web Storage]]></category>
		<guid isPermaLink="false">http://blog.mach3.jp/?p=3775</guid>

					<description><![CDATA[&#8220;U&#8221; は userData の &#8220;U&#8221;。 userData userData は、旧来の Internet Explorer で使用出来るローカルのストレージです。 ロー [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>&#8220;U&#8221; は userData の &#8220;U&#8221;。</p>



<figure class="wp-block-image"><img decoding="async" src="https://lh4.googleusercontent.com/-sHTfojjN8VA/UqR4lhb5EMI/AAAAAAAACYg/-W3cAHkju48/s400/ac2013-u.png" alt="U"/></figure>



<p></p>



<span id="more-3775"></span>



<h2 class="wp-block-heading">userData</h2>



<p><strong>userData</strong> は、旧来の Internet Explorer で使用出来るローカルのストレージです。 ローカルの記憶領域というと今では <a href="http://www.w3.org/TR/webstorage/">Web Storage</a> がありますが、 しばしばその代替として使用されています。</p>



<p>何が凄いのかというと、これが IE5（1999年）から実装されている点で、 Web黎明期を少し抜けたあたりで Web Storage に近しい物が既に存在していたという事になります。 一方の DOM Storage はIE8からサポートされている為あまり出番はないかもしれませんが、 いまだ息が絶えないIE6-7対応で活躍する事ができます。</p>



<h3 class="wp-block-heading">Cookie との比較</h3>



<p>Web Storage の代替として広く使われている Cookie と比較すると、容量と範囲で大きな差があります。</p>



<ul class="wp-block-list">
<li><strong>容量</strong>
<ul class="wp-block-list">
<li>userData: およそ1MB</li>



<li>Cookie: およそ5KB</li>
</ul>
</li>



<li><strong>範囲</strong>
<ul class="wp-block-list">
<li>userData: 同じディレクトリ内のみ</li>



<li>Cookie: フレキシブルに設定可能</li>
</ul>
</li>
</ul>



<p>容量は、5MBほど利用できる Web Storage には及びませんが、Cookie と比較するとかなり大きいです。 その半面、データを共有出来る範囲が同じディレクトリ内に限られてしまいます。 互いに一長一短なので、場面によってい使い分けたいところです。</p>



<h2 class="wp-block-heading">userData の使い方</h2>



<p>userData は IE独自の <strong>behavior</strong> でスタイル指定をして使います。 下の例では input 要素にしていますが、恐らくどの要素でも使えると思います。</p>


<pre class="wp-block-code"><span><code class="hljs language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"my-storage"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"behavior:url(#default#userData)"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">var</span> myStorage = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"my-storage"</span>);
    myStorage.load(<span class="hljs-string">"myStorageData"</span>);
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></span></pre>


<p><strong>#default#userData</strong> を behavior で指定した要素は userData を使用する為のメソッドが使えるようになります。</p>



<ul class="wp-block-list">
<li><strong>load(name)</strong>: ストレージからデータをロードする</li>



<li><strong>save(name)</strong>: ストレージにデータを保存する</li>



<li><strong>getAttribute(key)</strong>: 値を取得する</li>



<li><strong>setAttribute(key, value)</strong>: 値をセットする</li>



<li><strong>removeAttribute(key)</strong>: 値を削除する</li>
</ul>



<p>ストレージ名を &#8220;myStorageData&#8221; とし、適当な値を設定してみる例です。 ロードとセーブが都度必要になる以外は、別段注意すべき所はなさそうですね。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">myStorage.load(<span class="hljs-string">"myStorageData"</span>);
myStorage.setAttribute(<span class="hljs-string">"name"</span>, <span class="hljs-string">"john"</span>);
myStorage.setAttribute(<span class="hljs-string">"email"</span>, <span class="hljs-string">"john@example.com"</span>);
myStorage.save(<span class="hljs-string">"myStorageData"</span>);
</code></span></pre>


<p>ストレージに使用する要素を動的に生成する事もできますが、DOMに追加されていないと働かないので注意が必要です。 動的生成の際には <strong>addBehavior</strong> メソッドが便利です。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">var</span> myStorage = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"input"</span>);
myStorage.setAttribute(<span class="hljs-string">"type"</span>, <span class="hljs-string">"hidden"</span>);
myStorage.addBehavior(<span class="hljs-string">"#default#userData"</span>);
<span class="hljs-built_in">document</span>.body.appendChild(myStorage);
myStorage.load(<span class="hljs-string">"myStorageData"</span>);
</code></span></pre>


<h2 class="wp-block-heading">localStorage の polyfill を userData で書いてみる</h2>



<p>少し長くなりますが、IE7以下向けの localStorage の代替処理を書いてみます。 先述の通り、同じディレクトリ内でしかデータを共有する事は出来ません。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-comment">// Detect supports</span>
    <span class="hljs-keyword">if</span>(<span class="hljs-string">"localStorage"</span> <span class="hljs-keyword">in</span> <span class="hljs-built_in">window</span> || ! (<span class="hljs-string">"addBehavior"</span> <span class="hljs-keyword">in</span> <span class="hljs-built_in">document</span>.body)){
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// Create element for strage</span>
    <span class="hljs-keyword">var</span> createStorage = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">name</span>)</span>{
        <span class="hljs-keyword">var</span> input = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"input"</span>);
        <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"head"</span>)&#91;<span class="hljs-number">0</span>].appendChild(input);
        input.setAttribute(<span class="hljs-string">"type"</span>, <span class="hljs-string">"hidden"</span>);
        input.addBehavior(<span class="hljs-string">"#default#userData"</span>);
        input.load(name);
        input._commit = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
            <span class="hljs-keyword">this</span>.save(name);
        };
        <span class="hljs-keyword">return</span> input;
    };

    <span class="hljs-comment">// Storage and index object</span>
    <span class="hljs-keyword">var</span> storage = createStorage(<span class="hljs-string">"altLocalStorage"</span>);
    <span class="hljs-keyword">var</span> index = createStorage(<span class="hljs-string">"altLocalStorageKeys"</span>);

    <span class="hljs-comment">// Fetures for index</span>
    index._get = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
        <span class="hljs-keyword">var</span> keys = <span class="hljs-keyword">this</span>.getAttribute(<span class="hljs-string">"keys"</span>) || <span class="hljs-string">""</span>;
        <span class="hljs-keyword">if</span>(keys){ <span class="hljs-keyword">return</span> keys.split(<span class="hljs-string">","</span>); }
        <span class="hljs-keyword">return</span> &#91;];
    };
    index._indexOf = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key, keys</span>)</span>{
        <span class="hljs-keyword">var</span> i=<span class="hljs-number">0</span>; keys = keys || <span class="hljs-keyword">this</span>._get();
        <span class="hljs-keyword">for</span>(; i&lt;keys.length; i++){
            <span class="hljs-keyword">if</span>(keys&#91;i] === key){ <span class="hljs-keyword">return</span> i; }
        }
        <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
    };
    index._set = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">keys</span>)</span>{
        <span class="hljs-keyword">this</span>.setAttribute(<span class="hljs-string">"keys"</span>, keys.join(<span class="hljs-string">","</span>));
        <span class="hljs-keyword">this</span>._commit();
    };

    <span class="hljs-comment">// API</span>
    <span class="hljs-built_in">window</span>.localStorage = {
        <span class="hljs-attr">setItem</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key, value</span>)</span>{
            <span class="hljs-keyword">var</span> keys;
            <span class="hljs-keyword">if</span>(index._indexOf(key) &lt; <span class="hljs-number">0</span>){
                keys = index._get();
                keys.push(key);
                index._set(keys);
            }
            storage.setAttribute(key, value);
            storage._commit();
        },
        <span class="hljs-attr">getItem</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key</span>)</span>{
            <span class="hljs-keyword">return</span> storage.getAttribute(key);
        },
        <span class="hljs-attr">removeItem</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">key</span>)</span>{
            <span class="hljs-keyword">var</span> keys, i;
            keys = index._get(),
            i = index._indexOf(key, keys);
            <span class="hljs-keyword">if</span>(i &gt;= <span class="hljs-number">0</span>){
                keys.splice(i, <span class="hljs-number">1</span>);
                index._set(keys);
            }
            storage.removeAttribute(key);
            storage._commit();
        },
        <span class="hljs-attr">clear</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
            <span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>, keys = index._get();
            <span class="hljs-keyword">for</span>(; i&lt;keys.length; i++){
                storage.removeAttribute(keys&#91;i]);
            }
            storage._commit();
            index._set(&#91;]);
        }
    };
}());
</code></span></pre>


<p>保存されたデータを列挙する手段が見つからなかった為、キーを保存するストレージを別に作っています。 <strong>clear</strong> メソッドを実装しなければそれは必要ないので、半分以下のコード量に収まると思います。</p>



<p>余談ですが、IEの開発者ツールでモードを Internet Exlorer 7 にしても &#8220;localStorage&#8221; は実装されてしまっていますので、 上のコードはネイティブのIE7でないと検証する事が出来ません。</p>



<h2 class="wp-block-heading">参考資料</h2>



<ul class="wp-block-list">
<li><a href="http://msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx">userData Behavior (A, ABBR, ACRONYM, &#8230;)</a></li>



<li><a href="https://developer.mozilla.org/ja/docs/DOM/Storage">DOM Storage &#8211; DOM | MDN</a></li>



<li><a href="http://www.w3.org/TR/webstorage/">Web Storage</a></li>
</ul>



<h2 class="wp-block-heading">追記</h2>



<dl>
<dt>2014/01/23</dt>
<dd>コードの誤りを修正（urlの欠如）</dd>
</dl>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>&#034;Offline&#034; &#8211; Alphabetical Advent Calendar 2013</title>
		<link>https://blog.mach3.jp/2013/12/14/jaac2013-o-offline.html</link>
		
		<dc:creator><![CDATA[mach3]]></dc:creator>
		<pubDate>Sat, 14 Dec 2013 01:39:21 +0000</pubDate>
				<category><![CDATA[Laboratory]]></category>
		<category><![CDATA[Advent Calendar 2013]]></category>
		<category><![CDATA[applicationCache]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Offline]]></category>
		<category><![CDATA[Web Storage]]></category>
		<guid isPermaLink="false">http://blog.mach3.jp/?p=3732</guid>

					<description><![CDATA[&#8220;O&#8221; は Offline の &#8220;O&#8221;。 オフラインWebアプリケーション 旧来のいわゆる「Webアプリケーション」は、Webと繋がっていること、 つまりネットワークがオン [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>&#8220;O&#8221; は Offline の &#8220;O&#8221;。</p>



<figure class="wp-block-image"><img decoding="async" src="https://lh5.googleusercontent.com/-zOrs4xHvFEA/UqR4jppiyGI/AAAAAAAACYg/lZZfJorxJ-I/s400/ac2013-o.png" alt="O"/></figure>



<p></p>



<span id="more-3732"></span>



<h2 class="wp-block-heading">オフラインWebアプリケーション</h2>



<p>旧来のいわゆる「Webアプリケーション」は、Webと繋がっていること、 つまりネットワークがオンラインになっている状態で利用する事が前提でしたが、 昨今では <strong>applicationCache</strong> や <strong>Web Storage</strong> などを使用してオフラインでも動作する オフラインWebアプリケーションの構築も可能になってきています。</p>



<h2 class="wp-block-heading">オフライン / オンラインの判定</h2>



<p>まずはオンライン状態なのかオフライン状態なのかの確認ですが、 モダンな環境ならば <strong>navigator.onLine</strong> をチェックする事で出来る様です。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">if</span>(navigator.onLine){
    <span class="hljs-comment">// online</span>
} <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// offline</span>
}
</code></span></pre>


<p>ただ、この onLine は実装されていない環境があったり、 元々このプロパティはブラウザの「オフライン作業」のチェックを確認する物だったようで、 いくつかの環境では期待する挙動をしません。</p>



<p>そこで、実際にネットワークにつながっていて目的の場所にアクセスできるかどうかを確認する為に 次のようなコードを書いてみます。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">var</span> checkOnline = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">var</span> xhr, online = <span class="hljs-literal">true</span>;
    xhr = <span class="hljs-keyword">new</span> XMLHttpRequest();
    xhr.open(<span class="hljs-string">"HEAD"</span>, <span class="hljs-string">"/"</span>, <span class="hljs-literal">false</span>);
    <span class="hljs-keyword">try</span> { xhr.send(); }
    <span class="hljs-keyword">catch</span>(e){ online = <span class="hljs-literal">false</span>; }
    <span class="hljs-keyword">return</span> online;
};

checkOnline(); <span class="hljs-comment">// ネットワークに繋がっていれば true</span>
</code></span></pre>


<p>XMLHttpRequest でWebサイトのルートのヘッダを取得して、失敗した場合に「オフラインである」とみなしています。</p>



<p>期待する navigator.onLine をサポートしているかどうかを判別するのが難しかった為、 polyfill ではなく別名の関数として定義してみました。 （上のコードでは XMLHttpRequest を素のまま使っていますが、 古いIE等のXHRをサポートしない環境にはその為の対応が必要です。）</p>



<p>また、online イベントのようにオンライン状態が変更された時に処理を行いたい場合は、 これを定期的に監視してみます。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">var</span> onOnlineStateChange = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">callback, interval</span>)</span>{
    interval = interval || <span class="hljs-number">8000</span>;
    <span class="hljs-keyword">return</span> setInterval(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
        <span class="hljs-keyword">var</span> online = checkOnline();
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">window</span>.isOnline !== online){
            callback(online);
        }
        <span class="hljs-built_in">window</span>.isOnline = online;
    }, interval);
};

<span class="hljs-keyword">var</span> timer = onOnlineStateChange(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">online</span>)</span>{
    <span class="hljs-built_in">console</span>.log( online ? <span class="hljs-string">"オンラインです"</span> : <span class="hljs-string">"オフラインです"</span> );
});
</code></span></pre>


<p>8秒毎にチェックを行い、変更された場合に callback を実行します。 window を使ってグローバルを汚していますので注意が必要です。 また、きちんとイベントを発火させたい場合はもう少し長いコードになるでしょう。</p>



<h2 class="wp-block-heading">オフラインWebアプリケーションをサポートする技術</h2>



<h3 class="wp-block-heading">applicationCache</h3>



<p><strong>applicationCache</strong> は、Webコンテンツのローカルキャッシュをコントロールする事が出来る機能で、 キャッシュマニフェストファイル（*.appcache）を用意して、HTML要素の <strong>manifest</strong> 属性に記載する事で使えるようになります。</p>


<pre class="wp-block-code"><span><code class="hljs language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">manifest</span>=<span class="hljs-string">"myapp.appcache"</span>&gt;</span>
</code></span></pre>


<p>大まかな処理の流れとしては、ブラウザが <strong>myapp.appcache</strong> を読み込み、その中で指定されているファイルをローカルに保持し、 それらのファイルについてはネットワークにアクセスせずにローカルのキャッシュを使用するようになります。 つまりオフラインの状態でWebコンテンツが利用出来る様になるわけです。</p>



<p>ファイルの更新については少し注意が必要で、 キャッシュされたあとでリモートのファイルを更新しても、どこふく風でローカルのファイルを見続けてしまいます。</p>



<p>更新した事を通知する為には、 myapp.appcache の内容を更新する必要があります。 コメントで日付やバージョン等を記述しておくと更新を通知出来て都合がよさそうです。</p>


<pre class="wp-block-code"><span><code class="hljs language-php">CACHE MANIFEST
<span class="hljs-comment"># version 2013-12-14 12:34</span>
index.html
js/main.js
css/style.css

NETWORK:
*
</code></span></pre>


<p>マニフェストファイルの記法や注意事項などはこちらで。</p>



<ul class="wp-block-list">
<li><a href="https://developer.mozilla.org/ja/docs/Web/HTML/Using_the_application_cache">アプリケーションキャッシュの使用 &#8211; HTML | MDN</a></li>
</ul>



<h3 class="wp-block-heading">Web Storage</h3>



<p>Web Storage はブラウザから使用できるローカルのデータ保存領域で、 <strong>sessionStorage</strong> / <strong>localStorage</strong> として実装されています。 Cookie の様な物ですが利用可能な容量ははるかに大きく、モダンなデスクトップブラウザなら概ね 5M 程使う事ができます。 オフラインの場合にローカルに編集内容を保持しておいてオンラインになったらサーバに送って保存する、 といった使い方が期待されます。</p>



<p>sessionStorgae と localStorage はデータを保持する期間が異なる以外、使い方などはほぼ一緒です。</p>



<ul class="wp-block-list">
<li><strong>sessionStorage</strong> : タブ（あるいはウィンドウ）内のみで有効</li>



<li><strong>localStorage</strong> : 永続的に有効</li>
</ul>



<p>オフラインWebアプリケーションとしては localStorage が便利そうですね。 データの保存・取り出しは setItem / getItem を呼び出すだけの簡単設計です。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">localStorage.setItem(<span class="hljs-string">"foo"</span>, <span class="hljs-string">"bar"</span>);
localStorage.getItem(<span class="hljs-string">"foo"</span>); <span class="hljs-comment">// "bar"</span>
</code></span></pre>


<p>使い方・仕様などの詳細はこちらから。</p>



<ul class="wp-block-list">
<li><a href="https://developer.mozilla.org/ja/docs/DOM/Storage">DOM Storage &#8211; DOM | MDN</a></li>



<li><a href="http://dev.w3.org/html5/webstorage/">Web Storage</a></li>
</ul>



<h2 class="wp-block-heading">参考資料</h2>



<ul class="wp-block-list">
<li><a href="https://developer.mozilla.org/ja/docs/Online_and_offline_events">Online and offline events | MDN</a></li>



<li><a href="https://developer.mozilla.org/ja/docs/Web/HTML/Using_the_application_cache">アプリケーションキャッシュの使用 &#8211; HTML | MDN</a></li>



<li><a href="https://developer.mozilla.org/ja/docs/DOM/Storage">DOM Storage &#8211; DOM | MDN</a></li>



<li><a href="http://dev.w3.org/html5/webstorage/">Web Storage</a></li>
</ul>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
