前回 は、OdometerというWebアプリへの機能追加 を通して、Background Pages、Message Passingの詳細を解説しました。今回は、Odometerにさらに機能を追加する形でOptions Page、Web Storageについて解説していきたいと思います。
追加機能の概要
多くのWebアプリでは、使いやすいようにユーザー自身が各種設定を行うことが可能になっています。Odometerでもユーザービリティ向上のためにいくつかの設定項目を用意したいと思います。
例えばOdometerが目的地までの距離を通知する間隔は、目的地から1km圏内であれば200mごとに通知するように設定されています。これらをユーザーが任意の間隔で通知を受けられるように修正します。また、通知間隔以外にもデスクトップへの通知の有効/無効の切り替えやポップアップを表示している通知時間なども同時に設定できるように修正します。
設定画面の呼び出しには、Web AppsのOptions Pageという仕組みを利用し、設定値を保存する方法としてHTML5(広義の意味でのHTML5)のAPIであるWeb Storageを利用します。
図1 Odometer
図2 Odometer設定画面
Webアプリの構成
Webアプリを構成するファイルにoptions.htmlとその関連ファイルを追加します。options.htmlは、そのまま設定画面として表示されます。
manifest.json
{
"name" : "Odometer" ,
"description" : "距離計" ,
"version" : "0.3" ,
"app" : {
"launch" : {
"local_path" : "main.html"
}
},
"icons" : {
"16" : "icon_16.png" ,
"48" : "icon_48.png" ,
"128" : "icon_128.png"
},
"options_page" : "options.html" ,
"background_page" : "background.html" ,
"permissions" : [
"geolocation" ,
"notifications" ,
"background"
]
}
"options_page"に設定画面となる任意のHTMLファイルとして、今回追加したoptions.htmlを指定しています。
Options Page
Options Pageは、マニフェストファイルで指定されたHTMLファイルをWebアプリの設定画面として表示するだけの非常に単純な仕組みです。「 新しいタブ」ページのWebアプリの設定メニューから「オプション」をクリックすることで表示することができます。また、Chromeブラウザの設定メニューから「ツール」>「拡張機能」の「オプション」リンクからも同様に表示することができます。ここで表示された設定画面は単なるHTMLファイルなので 、 Webアプリの設定項目や設定の保存/反映は自分で記述する必要があります。
図3 「 新しいタブ」ページからのオプションの表示
図4 「 拡張機能」ページからのオプションの表示
Odometerの設定画面として、以下の3つの設定項目を用意しました。設定項目はフォームで作成し、後述するWeb Storageを使って設定を保存、参照します。
デスクトップへの通知の有効/無効
通知時間(秒)
目的地~1km圏内、1km~10km圏内、10km圏外でのそれぞれの通知間隔(mまたはkmで指定)
今回は利用しませんが、Fancy Settings というChromeの設定画面によく似た設定画面を生成するフレームワークもありますので、興味のある方は利用してみてください。
図5 Fancy Settingsで生成した設定画面
options.html
<!DOCTYPE html>
< html lang = "ja" >
< head >
< meta charset = "utf-8" >
< title > Odometer設定 </ title >
< link rel = "stylesheet" href = "css/reset.css" >
< link rel = "stylesheet" href = "css/options.css" >
< script src = "js/options.js" ></ script >
</ head >
< body >
< header >
< h1 > Odometer設定 </ h1 >
</ header >
< section >
< h2 > 通知設定 </ h2 >
< div class = "internal" >
< div class = "setting" >
< p >
< label for = "notify-setting" > デスクトップへ通知: </ label >
< input type = "checkbox" id = "notify-setting" checked >
</ p >
< p >
< label for = "display-time" > 通知時間: </ label >
< input type = "number" min = "0" step = "1" value = "5" id = "display-time" > 秒
< span class = "aside" > ※ 0秒を指定すると通知は自動的に閉じられません </ span >
</ p >
</ div >
< div class = "detail-setting" >
< table >
< tr >
< th > 通知範囲 </ th >
< th > 通知間隔 </ th >
</ tr >
< tr >
< td > 目的地~1km園内 </ td >
< td >
< input type = "number" value = "100" min = "0.001" step = "1" id = "short" >
< select id = "short-unit" >
< option value = "m" selected > m </ option >
< option value = "km" > km </ option >
</ select >
ごとに通知する
</ td >
</ tr >
< tr >
< td > 1km~10km圏内 </ td >
< td >
< input type = "number" value = "1" min = "0.001" step = "1" id = "middle" >
< select id = "middle-unit" >
< option value = "m" > m </ option >
< option value = "km" selected > km </ option >
</ select >
ごとに通知する
</ td >
</ tr >
< tr >
< td > 10km圏外 </ td >
< td >
< input type = "number" value = "5" min = "0.001" step = "1" id = "long" >
< select id = "long-unit" >
< option value = "m" > m </ option >
< option value = "km" selected > km </ option >
</ select >
ごとに通知する
</ td >
</ tr >
</ table >
</ div >
</ div >
< div class = "buttons" >
< input type = "submit" value = "設定" id = "apply" >
< input type = "reset" value = "キャンセル" id = "cancel" >
</ div >
</ section >
</ body >
</ html >
Web Storage
Web Storageとは、データをブラウザ上に保存するため仕組みです。ブラウザを閉じてもデータが保持されるlocalStorageと、同一セッションで有効でブラウザを閉じるとデータが消去されるsessionStorageの2種類があります。今回は設定を保存することが目的のため、localStorageを利用します。
Web Storageとクッキーとの違い
Web StorageはAPIがシンプルなため、簡単にデータを保存することができます。また、クッキーはサーバー側へリクエストを送信するたびにクッキーの内容がすべて送られているため通信量が増えてしまいますが、Web Storageではローカルでやり取りしているだけなので余計な通信が発生しません。
データの保存と参照
データの保存と参照には、window.localStorage以下のsetItem()メソッドとgetItem()メソッドを使用します。データは、キーと値をペアとしたものになります。保存できる値は、仕様上はJavaScriptオブジェクトが可能ですが、現状の実装では文字列のみ可能となっています。localStorageとsessionStorageはデータのスコープが違うだけでAPIは同一ですので、もしsessionStorageを利用する場合でも同じ記述方法で問題ありません。また、いずれも保存できるデータ量は、5MBとなっています。
options.js(設定の保存)
var ranges = [
'short' ,
'middle' ,
'long'
];
document . getElementById ( 'apply' ). addEventListener ( 'click' , function (){
var setting = {
notify : document . getElementById ( 'notify-setting' ). checked ,
display : parseInt ( document . getElementById ( 'display-time' ). value , 10 )
};
for ( var i = 0 , len = ranges . length ; i < len ; i ++ ) {
var distance = parseFloat ( document . getElementById ( ranges [ i ]). value , 10 );
if ( document . getElementById ( ranges [ i ] + '-unit' ). value === 'm' ) {
distance /= 1000 ;
}
setting [ ranges [ i ]] = distance ;
}
localStorage . setItem ( 'setting' , JSON . stringify ( setting ));
}, false );
「設定」ボタンのクリック時にsetting変数を用意し、設定オブジェクトとして、それぞれのフォームから取ってきた値を格納しています。この設定オブジェクトをlocalStorage.setItem()メソッドから“ setting” というキーで保存しています。また、保存できる値が文字列のみとなっているため、設定オブジェクトをJSON.stringify()メソッドを使って文字列に変換して格納しています。
options.js(設定の参照)
function init (){
var setting = JSON . parse ( localStorage . getItem ( 'setting' ));
document . getElementById ( 'notify-setting' ). checked = setting . notify ;
document . getElementById ( 'display-time' ). value = setting . display ;
for ( var i = 0 , len = ranges . length ; i < len ; i ++ ) {
var distance = setting [ ranges [ i ]];
if ( distance < 1 ) {
document . getElementById ( ranges [ i ] + '-unit' ). selectedIndex = 0 ;
document . getElementById ( ranges [ i ]). value = ( distance * 1000 );
} else {
document . getElementById ( ranges [ i ] + '-unit' ). selectedIndex = 1 ;
document . getElementById ( ranges [ i ]). value = distance ;
}
}
}
設定画面のイニシャルセットとして、保存されている設定をlocalStorage.getItem()メソッドで参照して各フォームへセットしています。今度は逆に、保存されている値が文字列となっているためJSON.parse()メソッドを使ってJavaScriptオブジェクトに変換しています。
ここでは、getItem()メソッドとsetItem()メソッドを使っていますが、ほかにも以下のような記述方法でも同様のことができます。お好みの方法で記述してください。
localStorage . setting = JSON . stringfy ( setting );
localStorage [ "setting" ] = JSON . stringfy ( setting );
var setting = JSON . parse ( localStorage . setting );
var setting = JSON . parse ( localStorage [ "setting" ]);
表1 localStorage/sessionStorage
メソッド/プロパティ 説明
length ストレージの長さを返す
key(n) n番目のキーを返す
getItem(key) キーに対応する値を返す
setItem(key, value) キーと値のペアを保存する
removeItem(key) キーと対応する値を削除する
clear() ストレージを消去する
設定の反映
実際に設定された値を使って通知を行うように変更します。設定値をキャッシュする方法もありますが、今回は設定が変更された際にすぐに反映されるように都度参照しています。
background.js(デフォルト設定)
if ( ! localStorage . getItem ( 'setting' ) ) {
var setting = {
notify : true ,
display : 5 ,
short : 0.2 ,
middle : 1 ,
long : 5
};
localStorage . setItem ( 'setting' , JSON . stringify ( setting ));
}
まだ何も設定されていない最初のアクセスの際にデフォルト値を利用するようにします。“ setting” をキーとした値がなければ改めてデフォルト設定を保存しています。
background.js(デスクトップへの通知部分を抜粋)
var watchId = 0 ;
function startWatchPosition ( sender , sendResponse ){
var setting = JSON . parse ( localStorage . getItem ( 'setting' ));
if ( setting . notify ) {
var threshold = 0 ;
if ( distance < 1 ) {
threshold = setting . short ;
} else if ( distance < 10 ) {
threshold = setting . middle ;
} else {
threshold = setting . long ;
}
var notifiedKey = Math . floor ( distance / threshold ) * threshold ;
if ( ! notified [ notifiedKey ] ) {
notify ( '目的地までの距離' , '約 ' + distance + ' km' , setting . display );
notified [ notifiedKey ] = true ;
}
}
~省略~
}
以前より変更された部分は、デスクトップへの通知を行う前に設定を取得し、デスクトップへの通知自体を行うかどうか決定するように処理を追加しています。また、これまで固定値で判定していた箇所を設定値で判定するように変更しています。
これで、Odometerに設定画面が追加され、ユーザー自身で各種設定を行えるようになりました。Web Storageは、Webアプリの設定に限らず、各種データを保存する方法として利用できるので是非活用してください。
まとめ
今回は、Odometerに設定画面を追加し、Options PageとWeb Storageの詳細を解説しました。次回も引き続きさまざまなAPIを解説していきたいと思います。