<?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>SCRAPBLOG</title>
	<atom:link href="http://www.xuldev.org/blog/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.xuldev.org/blog</link>
	<description>http://www.xuldev.org/blog/</description>
	<lastBuildDate>Thu, 29 Jul 2010 16:04:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Jetpack SDK 0.5 の Tabs API</title>
		<link>http://www.xuldev.org/blog/?p=822</link>
		<comments>http://www.xuldev.org/blog/?p=822#comments</comments>
		<pubDate>Mon, 19 Jul 2010 17:22:24 +0000</pubDate>
		<dc:creator>Gomita</dc:creator>
				<category><![CDATA[Jetpack]]></category>
		<category><![CDATA[SDK]]></category>

		<guid isPermaLink="false">http://www.xuldev.org/blog/?p=822</guid>
		<description><![CDATA[Jetpack SDK 0.5 で追加された Tabs API を使用すると、指定したURLを新しいタブやウィンドウで開いたり、各タブ内に表示されたページのDOMへアクセスしたり、タブの開閉やページの読み込みなどのイベントに対してコールバック処理を追加したりすることが可能です。 Tabs API を使用するには、はじめに require 関数でモジュールをインポートします。 var tabs = require("tabs"); タブを開く Tabs API の open メソッドで、指定したURLを新しいタブやウィンドウで開くことが可能です。似た機能を持ったAPIとして、 tab-browser API の addTab メソッドもありますが、 Tabs API の open メソッドを使用することが推奨されています。 open メソッドの引数に直接URLを指定した場合、新しいタブへ開くと同時にフォーカスします。 tabs.open("http://www.example.com/"); 一方、引数を下記のようなオブジェクト形式とした場合、指定したURLを新しいバックグラウンドのタブで開きます。 tabs.open({ url: "http://www.example.com/", inBackground: true }); 各タブの情報を取得する・タブ内のページのDOMへアクセスする Tabs API の activeTab プロパティによって現在のタブ（Tab オブジェクト）を取得したり、 Tabs API のオブジェクト自体を for ～ in [...]]]></description>
			<content:encoded><![CDATA[<p>Jetpack SDK 0.5 で追加された <a href="https://jetpack.mozillalabs.com/sdk/0.5/docs/#module/jetpack-core/tabs">Tabs API</a> を使用すると、指定したURLを新しいタブやウィンドウで開いたり、各タブ内に表示されたページのDOMへアクセスしたり、タブの開閉やページの読み込みなどのイベントに対してコールバック処理を追加したりすることが可能です。</p>
<p>Tabs API を使用するには、はじめに require 関数でモジュールをインポートします。</p>
<pre lang="JavaScript">
var tabs = require("tabs");
</pre>
<h4>タブを開く</h4>
<p>Tabs API の <code>open</code> メソッドで、指定したURLを新しいタブやウィンドウで開くことが可能です。似た機能を持ったAPIとして、 <a href="https://jetpack.mozillalabs.com/sdk/0.5/docs/#module/jetpack-core/tab-browser">tab-browser API</a> の <code>addTab</code> メソッドもありますが、 Tabs API の open メソッドを使用することが推奨されています。</p>
<p><code>open</code> メソッドの引数に直接URLを指定した場合、新しいタブへ開くと同時にフォーカスします。</p>
<pre lang="JavaScript">
tabs.open("http://www.example.com/");
</pre>
<p>一方、引数を下記のようなオブジェクト形式とした場合、指定したURLを新しいバックグラウンドのタブで開きます。</p>
<pre lang="JavaScript">
tabs.open({
	url: "http://www.example.com/",
	inBackground: true
});
</pre>
<h4>各タブの情報を取得する・タブ内のページのDOMへアクセスする</h4>
<p>Tabs API の <code>activeTab</code> プロパティによって現在のタブ（Tab オブジェクト）を取得したり、 Tabs API のオブジェクト自体を for ～ in ループで回すことで全ウィンドウ内の全タブ（Tab オブジェクト）を列挙したりすることが可能です。 Tab オブジェクトは、 <code>title</code> プロパティでタブのタイトルやURLを取得したり、 <code>contentDocument</code> プロパティでタブ内に表示されたページのDOMへアクセスしたりすることが可能です。</p>
<p>下記は、現在のタブのタイトルとURLを取得し、現在のタブ内に表示されたページのDOMの window.alert メソッドを使って表示させる例です。</p>
<pre lang="JavaScript">
var tab = tabs.activeTab;
tab.contentWindow.alert(tab.title + "\n" + tab.location);
</pre>
<p>Tab オブジェクトの面白い機能として、 <code>thumbnail</code> プロパティでタブ内に表示されたページのサムネイル画像を html:canvas 要素として取得することが可能です。下記は、全ウィンドウ内の全タブについてサムネイル画像を取得して data: URL へ変換し、それらを表示するHTMLを新しいウィンドウで開く例です。</p>
<pre lang="JavaScript">
var html = "";
for (var tab in tabs) {
	html += '&lt;img src="' + tab.thumbnail.toDataURL() + '"/&gt;';
}
tabs.open({
	url: "data:text/html,&lt;html&gt;&lt;body&gt;" + html + "&lt;/body&gt;&lt;/html&gt;";,
	inNewWindow: true
});
</pre>
<p><a href="../misc/wp/Jetpack-TabsAPI.png" rel="lightbox"><img src="../misc/wp/Jetpack-TabsAPI_small.png" width="200" height="150" /></a></p>
<h4>タブを閉じる・移動する</h4>
<p>Tab オブジェクトには、タブを閉じる <code>close</code>、タブを同一ウィンドウ内の別の位置へ移動する <code>move</code>、タブへフォーカスする <code>activate</code> などのメソッドもあります。下記は、現在のタブを閉じる例です。</p>
<pre lang="JavaScript">
tabs.activeTab.close();
</pre>
<h4>タブ関連イベントへのコールバック処理</h4>
<p>onOpen（タブを開いたとき）, onClose（タブを閉じたとき）, onActivate（アクティブなタブが変化したとき）, onReady（タブ内のページのDOMツリー構築時 ＝ DOMContentLoaded イベント発生時）, onPaint（タブ内のページで再描画発生時 ＝ MozAfterPaint イベント発生時）などに対してコールバック処理を追加することができます。下記は、タブ内のページのDOMツリー構築完了時に、そのページのURLをコンソールへ表示する例です。</p>
<pre lang="JavaScript">
tabs.onReady = function(tab) {
	console.log("onReady: " + tab.location.href);
};
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.xuldev.org/blog/?feed=rss2&amp;p=822</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jetpack SDK 0.5 の Unload API</title>
		<link>http://www.xuldev.org/blog/?p=846</link>
		<comments>http://www.xuldev.org/blog/?p=846#comments</comments>
		<pubDate>Fri, 16 Jul 2010 23:30:54 +0000</pubDate>
		<dc:creator>Gomita</dc:creator>
				<category><![CDATA[Jetpack]]></category>
		<category><![CDATA[SDK]]></category>

		<guid isPermaLink="false">http://www.xuldev.org/blog/?p=846</guid>
		<description><![CDATA[Jetpack SDK の Unload API を使用すると、以下の例のように Firefox の終了や拡張機能の無効化などのシグナルを検知してコールバック処理を実行することが可能となります。 require("unload").when(function(reason) { switch (reason) { case "disable": // 拡張機能が無効化される直前に実行する処理 break; case "uninstall": // 拡張機能が削除される直前に実行する処理 break; case "shutdown": // アプリケーション終了直前に実行する処理 break; } }); Firefox 3.6 以下ではアドオンマネージャで該当する拡張機能の「無効化」または「削除」ボタンを押下して Firefox を終了または再起動する直前にコールバック処理が実行されるのに対して、 Firefox 4.0b2 以上では「無効化」または「削除」ボタンを押下した直後にコールバック処理が実行されます。]]></description>
			<content:encoded><![CDATA[<p>Jetpack SDK の <a href="https://jetpack.mozillalabs.com/sdk/0.5/docs/#module/jetpack-core/unload">Unload API</a> を使用すると、以下の例のように Firefox の終了や拡張機能の無効化などのシグナルを検知してコールバック処理を実行することが可能となります。</p>
<pre lang="JavaScript">
require("unload").when(function(reason) {
	switch (reason) {
		case "disable":
			<span class="code-comment">// 拡張機能が無効化される直前に実行する処理</span>
			break;
		case "uninstall":
			<span class="code-comment">// 拡張機能が削除される直前に実行する処理</span>
			break;
		case "shutdown":
			<span class="code-comment">// アプリケーション終了直前に実行する処理</span>
			break;
	}
});
</pre>
<p>Firefox 3.6 以下ではアドオンマネージャで該当する拡張機能の「無効化」または「削除」ボタンを押下して Firefox を終了または再起動する直前にコールバック処理が実行されるのに対して、 Firefox 4.0b2 以上では「無効化」または「削除」ボタンを押下した直後にコールバック処理が実行されます。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuldev.org/blog/?feed=rss2&amp;p=846</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jetpack SDK 0.5 の Selection API</title>
		<link>http://www.xuldev.org/blog/?p=839</link>
		<comments>http://www.xuldev.org/blog/?p=839#comments</comments>
		<pubDate>Wed, 14 Jul 2010 15:12:00 +0000</pubDate>
		<dc:creator>Gomita</dc:creator>
				<category><![CDATA[Jetpack]]></category>
		<category><![CDATA[SDK]]></category>

		<guid isPermaLink="false">http://www.xuldev.org/blog/?p=839</guid>
		<description><![CDATA[Jetpack SDK 0.5 で追加された Selection API を使用すると、選択範囲の取得や変更などが可能となります。 Selection API を使用するためには、はじめに require 関数でモジュールをインポートします。 var selection = require("selection"); 選択範囲の取得 Selection API の text および html プロパティで選択範囲の文字列あるいはHTMLソースを取得・変更することが可能です。また、Ctrlキーを押下しながら複数の範囲を選択した場合、 contigious プロパティが false となります。この時、 Selection API のオブジェクト自体に対して for ～ in ループで個々のサブ選択範囲（Selection オブジェクト）を取得することが可能です。 以下は、選択範囲が複数ある場合を考慮し、全ての選択範囲のHTMLソースをコンソールへ出力する例です。 if (selection.contiguous) { // 選択範囲がひとつだけの場合 console.log(selection.html); } else { // 複数の選択範囲がある場合 for (var subsel in selection) { console.log(subsel.html); [...]]]></description>
			<content:encoded><![CDATA[<p>Jetpack SDK 0.5 で追加された <a href="https://jetpack.mozillalabs.com/sdk/0.5/docs/#module/jetpack-core/selection">Selection API</a> を使用すると、選択範囲の取得や変更などが可能となります。</p>
<p>Selection API を使用するためには、はじめに require 関数でモジュールをインポートします。</p>
<pre lang="JavaScript">
var selection = require("selection");
</pre>
<h4>選択範囲の取得</h4>
<p>Selection API の <code>text</code> および <code>html</code> プロパティで選択範囲の文字列あるいはHTMLソースを取得・変更することが可能です。また、Ctrlキーを押下しながら複数の範囲を選択した場合、 <code>contigious</code> プロパティが false となります。この時、 Selection API のオブジェクト自体に対して for ～ in ループで個々のサブ選択範囲（Selection オブジェクト）を取得することが可能です。</p>
<p>以下は、選択範囲が複数ある場合を考慮し、全ての選択範囲のHTMLソースをコンソールへ出力する例です。</p>
<pre lang="JavaScript">
if (selection.contiguous) {
	<span class="code-comment">// 選択範囲がひとつだけの場合</span>
	console.log(selection.html);
}
else {
	<span class="code-comment">// 複数の選択範囲がある場合</span>
	for (var subsel in selection) {
		console.log(subsel.html);
	}
}
</pre>
<h4>範囲を選択したときのコールバック処理</h4>
<p><code>onSelect</code> プロパティによって、範囲を選択したときのコールバック処理を追加することが可能です。以下は、範囲を選択した時に、その選択範囲を &lt;span&gt; タグで囲み、蛍光ペンで着色したような表示にする例です。</p>
<pre lang="JavaScript">
selection.onSelect = function() {
	selection.html = '&lt;span style="background-color: yellow;"&gt;' + selection.html + '&lt;/span&gt;';
};
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.xuldev.org/blog/?feed=rss2&amp;p=839</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jetpack SDK 0.5 の Reuqest API</title>
		<link>http://www.xuldev.org/blog/?p=807</link>
		<comments>http://www.xuldev.org/blog/?p=807#comments</comments>
		<pubDate>Mon, 12 Jul 2010 15:05:15 +0000</pubDate>
		<dc:creator>Gomita</dc:creator>
				<category><![CDATA[Jetpack]]></category>
		<category><![CDATA[SDK]]></category>

		<guid isPermaLink="false">http://www.xuldev.org/blog/?p=807</guid>
		<description><![CDATA[Jetpack SDK 0.5 で追加された Request API を使用すると、 XMLHttpRequest によってWebサーバとデータを送受信する処理をより簡単に実装できます。特に、レスポンスがJSONかXML形式であるようなWebサービスのAPIを利用する場合に重宝しそうです。 この記事では、 Request API を使い、Twitter でキーワード「Firefox 4」を含むツイートの検索結果をコンソールへ列挙する例を紹介します。 Twitter のAPI仕様 実装に入る前に、 Twitter の検索用APIの仕様を簡単に示しておきます。 リクエスト キーワード xxx で検索する場合、以下のようなURLへGETメソッドで送信する。http://search.twitter.com/search.json?q=xxx レスポンス キーワードにマッチしたツイートのデータが、下記のようなJSON形式で返る。 { "results": [ { "text": "（１番目のツイートの内容）", "from_user": "（１番目のツイートの発言者）" ... }, { "text": "（２番目のツイートの内容）", "from_user": "（２番目のツイートの発言者）" ... }, { "text": "（３番目のツイートの内容）", "from_user": "（３番目のツイートの発言者）" ... }, ... ] } 実装 まず、 [...]]]></description>
			<content:encoded><![CDATA[<p>Jetpack SDK 0.5 で追加された <a href="https://jetpack.mozillalabs.com/sdk/0.5/docs/#module/jetpack-core/request">Request API</a> を使用すると、 XMLHttpRequest によってWebサーバとデータを送受信する処理をより簡単に実装できます。特に、レスポンスがJSONかXML形式であるようなWebサービスのAPIを利用する場合に重宝しそうです。</p>
<p>この記事では、 Request API を使い、Twitter でキーワード「Firefox 4」を含むツイートの検索結果をコンソールへ列挙する例を紹介します。</p>
<h4>Twitter のAPI仕様</h4>
<p>実装に入る前に、 <a href="http://apiwiki.twitter.com/Twitter-Search-API-Method%3A-search">Twitter の検索用APIの仕様</a>を簡単に示しておきます。</p>
<h5>リクエスト</h5>
<p>キーワード <em>xxx</em> で検索する場合、以下のようなURLへGETメソッドで送信する。<br/>http://search.twitter.com/search.json?q=<em>xxx</em></p>
<h5>レスポンス</h5>
<p>キーワードにマッチしたツイートのデータが、下記のようなJSON形式で返る。</p>
<pre>
{
    "results": [
        { "text": "（１番目のツイートの内容）", "from_user": "（１番目のツイートの発言者）" ... },
        { "text": "（２番目のツイートの内容）", "from_user": "（２番目のツイートの発言者）" ... },
        { "text": "（３番目のツイートの内容）", "from_user": "（３番目のツイートの発言者）" ... },
        ...
    ]
}
</pre>
<h4>実装</h4>
<p>まず、 require 関数でモジュールをインポートします。</p>
<pre code="JavaScript">
var requests = require("request");
</pre>
<p>次に、 Request APIの <code>Request</code> コンストラクタを用いて、 Request オブジェクトのインスタンスを生成します。コンストラクタの引数には、以下のプロパティを有するオブジェクトを渡します。</p>
<table class="list">
<tr>
<th>プロパティ</th>
<th>概要</th>
</tr>
<tr>
<td><code>url</code></td>
<td>データ送信先のURL</td>
</tr>
<tr>
<td><code>onComplete</code></td>
<td>データ受信時（XHRでいうところの readyState == 4）のコールバック処理</td>
</tr>
<tr>
<td><code>headers</code></td>
<td>必要に応じてリクエストヘッダ（User-Agent や Referer）をオブジェクト形式でセットする。例：<br /><code>headers: { "User-Agent": "MyApp", Referer: "http://..." },</td>
</tr>
<tr>
<td><code>content</code></td>
<td>必要に応じてリクエストのパラメータをオブジェクト形式でセットする。</td>
</tr>
<tr>
<td><code>contentType</code></td>
<td>必要に応じてHTTPヘッダの Content-Type の値をセットする。<br />デフォルトでは application/x-www-form-urlencoded</td>
</tr>
</table>
<p>生成した Request インスタンスの <code>get</code> メソッドを呼び出すと、GETメソッドでリクエストが送信されます。なお、 <code>post</code> メソッドを呼び出すと、POSTメソッドでリクエストが送信されます。</p>
<pre lang="JavaScript">
<span class="code-comment">// Request インスタンスの生成</span>
var request = requests.Request({
    url: "http://search.twitter.com/search.json",
    content: { q: "Firefox 4" },
    onComplete: function () {
        <span class="code-comment">// ToDo</span>
    }
});
<span class="code-comment">// GETメソッドで送信</span>
request.get();
</pre>
<p>Webサーバからのレスポンスが返って <code>onComplete</code> メソッドがコールバックされると、 Request インスタンスの <code>response</code> プロパティからレスポンス内容（Response オブジェクト）を取得することができるようになります。 Response オブジェクトは色々なプロパティを有し、 <code>json</code> プロパティや <code>xml</code> プロパティでレスポンスのボディ部をJSONあるいはXML形式でパースした結果を取得したり、 <code>headers</code> プロパティでレスポンスのヘッダ部の各フィールド値を取得したりすることが可能です。</p>
<p>今回はレスポンスのボディ部をJSON形式でパースし、前述のAPI仕様にあるとおり "results" プロパティでツイートのデータの配列を取得し、配列の各要素に対して "from_user", "text" プロパティで発言者と発言内容を取得します。</p>
<pre>
    onComplete: function () {
        var results = this.response.json.results;
        results.forEach(function(result) {
            console.log("user: " + result.from_user);
            console.log("text: " + result.text);
        });
    }
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.xuldev.org/blog/?feed=rss2&amp;p=807</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jetpack SDK 0.4 の Page Worker API</title>
		<link>http://www.xuldev.org/blog/?p=792</link>
		<comments>http://www.xuldev.org/blog/?p=792#comments</comments>
		<pubDate>Mon, 12 Jul 2010 08:57:04 +0000</pubDate>
		<dc:creator>Gomita</dc:creator>
				<category><![CDATA[Jetpack]]></category>
		<category><![CDATA[SDK]]></category>

		<guid isPermaLink="false">http://www.xuldev.org/blog/?p=792</guid>
		<description><![CDATA[HTTP(S)によりWebサーバとデータを送受信するには、 xhr API で XMLHttpRequest のインスタンスを生成する方法や、 Jetpack SDK 0.5 で追加された Request API を使用する方法があります。しかし、これらのAPIではWebサーバからのレスポンスがHTMLデータだった場合、特定のノードにある文字列を抽出したりする処理がやや困難となります。 一方、 Jetpack SDK 0.4 で追加された Page Worker API を用いると、不可視のフレーム（iframe 要素）内に指定したURLのHTMLドキュメントをロードし、パースされた結果をDOM操作することが可能となります。この記事では、 Page Worker API を用いて Wikipedia の Internet に関するページを不可視のフレームに読み込んで見出し（H2 > SPAN要素）を列挙する例を紹介します。 基本的な使い方 まず、 require 関数でモジュールをインポートします。 var pageWorker = require("page-worker"); Page Worker APIの Page コンストラクタを用いて、 Page オブジェクトのインスタンスを生成します。コンストラクタの引数には、以下のプロパティを有するオブジェクトを渡します。 プロパティ 概要 content 不可視のフレームにロードするURL、またはHTMLソース onReady ロード完了時のコールバック処理 allow [...]]]></description>
			<content:encoded><![CDATA[<p>HTTP(S)によりWebサーバとデータを送受信するには、 <a href="https://jetpack.mozillalabs.com/sdk/0.5/docs/#module/jetpack-core/xhr">xhr API</a> で XMLHttpRequest のインスタンスを生成する方法や、 Jetpack SDK 0.5 で追加された <a href="https://jetpack.mozillalabs.com/sdk/0.5/docs/#module/jetpack-core/request">Request API</a> を使用する方法があります。しかし、これらのAPIではWebサーバからのレスポンスがHTMLデータだった場合、特定のノードにある文字列を抽出したりする処理がやや困難となります。</p>
<p>一方、 Jetpack SDK 0.4 で追加された <a href="https://jetpack.mozillalabs.com/sdk/0.5/docs/#module/jetpack-core/page-worker">Page Worker API</a> を用いると、不可視のフレーム（iframe 要素）内に指定したURLのHTMLドキュメントをロードし、パースされた結果をDOM操作することが可能となります。この記事では、 Page Worker API を用いて Wikipedia の Internet に関するページを不可視のフレームに読み込んで見出し（<code>H2 > SPAN</code>要素）を列挙する例を紹介します。</p>
<h4>基本的な使い方</h4>
<p>まず、 require 関数でモジュールをインポートします。</p>
<pre code="JavaScript">
var pageWorker = require("page-worker");
</pre>
<p>Page Worker APIの <code>Page</code> コンストラクタを用いて、 Page オブジェクトのインスタンスを生成します。コンストラクタの引数には、以下のプロパティを有するオブジェクトを渡します。</p>
<table class="list">
<tr>
<th>プロパティ</th>
<th>概要</th>
</tr>
<tr>
<td><code>content</code></td>
<td>不可視のフレームにロードするURL、またはHTMLソース</td>
</tr>
<tr>
<td><code>onReady</code></td>
<td>ロード完了時のコールバック処理</td>
</tr>
<tr>
<td><code>allow</code></td>
<td>不可視のフレーム内でのスクリプト実行を許可するかどうかなどを指定するためのオプション。<br /><code>allow: { script: false }</code> でスクリプトの実行を不許可に設定することが可能。</td>
</tr>
</table>
<p>生成した Page インスタンスを <code>add</code> メソッドへ渡すと、不可視のフレーム内への読み込みが開始されます。</p>
<pre lang="JavaScript">
var page = pageWorker.Page({
    content: "http://en.wikipedia.org/wiki/Internet",
    onReady: function() {
        <span class="code-comment">// ToDo</span>
    }
});
pageWorker.add(page);
</pre>
<p>不可視のフレームへの読み込みが完了すると、 Page インスタンスの <code>window</code> および <code>document</code> プロパティ経由で不可視のフレーム内のDOMへアクセスすることができるようになります。以下の例では、不可視のフレームへの読み込み完了時、 HTMLのURLおよびタイトルを取得してコンソールへ表示し、さらにH2要素直下にあるSPAN要素の中身の文字列を列挙して表示します。</p>
<pre>
    onReady: function() {
        var url = this.window.location.href;
        var title = this.document.title;
        console.log(url + "\n" + title);
        var elts = this.document.querySelectorAll("h2 > span");
        Array.forEach(elts, function(elt) {
            console.log(elt.textContent);
        });
        pageWorker.remove(this);
    }
</pre>
<p>なお、 <code>onReady</code> の最後で Page オブジェクトのインスタンス自身を PageWorker の <code>remove</code> メソッドへ渡すことで、 <code>window</code> および <code>document</code> プロパティが削除され、不可視のフレーム内でのページ読み込みに使用されたメモリが解放されます。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuldev.org/blog/?feed=rss2&amp;p=792</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jetpack SDK 0.4 の Simple Storage API</title>
		<link>http://www.xuldev.org/blog/?p=783</link>
		<comments>http://www.xuldev.org/blog/?p=783#comments</comments>
		<pubDate>Thu, 08 Jul 2010 22:57:06 +0000</pubDate>
		<dc:creator>Gomita</dc:creator>
				<category><![CDATA[Jetpack]]></category>

		<guid isPermaLink="false">http://www.xuldev.org/blog/?p=783</guid>
		<description><![CDATA[拡張機能の設定値のような少量のデータを保存する際には Preferences Service API を使用しますが、より多くのデータを永続的に（Firefox を終了しても保持されるように）保存するには、 Simple Storage API が便利です。 基本的な使い方 はじめに require 関数でライブラリをインポートします。 var simpleStorage = require("simple-storage"); もっとも単純な方法は、 storage プロパティへ直接値をセットする方式です。以下は "test" という文字列を保存した後、値を取り出す例です。 simpleStorage.storage = "test"; console.log(simpleStorage.storage); // test 文字列だけでなく、数値、配列、オブジェクトなどをセットして保存可能です。 simpleStorage.storage = { "foo": 100, "bar": 200 }; console.log(simpleStorage.storage.foo); // 100 上記は以下のように書くことも可能です。 simpleStorage.storage.foo = 100; simpleStorage.storage.bar = 200; データの保存先 Simple Storage APIを使って保存したデータは、プロファイルフォルダ配下の jetpack\{パッケージマニフェストのID}\simple-storage\store.json へJSON形式で保存されます。また、ファイルへの出力タイミングは Jetpack [...]]]></description>
			<content:encoded><![CDATA[<p>拡張機能の設定値のような少量のデータを保存する際には <a href="https://jetpack.mozillalabs.com/sdk/0.4/docs/#module/jetpack-core/preferences-service">Preferences Service API</a> を使用しますが、より多くのデータを永続的に（Firefox を終了しても保持されるように）保存するには、 <a href="https://jetpack.mozillalabs.com/sdk/0.5/docs/#module/jetpack-core/simple-storage">Simple Storage API</a> が便利です。</p>
<h4>基本的な使い方</h4>
<p>はじめに require 関数でライブラリをインポートします。</p>
<pre lang="JavaScript">
var simpleStorage = require("simple-storage");
</pre>
<p>もっとも単純な方法は、 <code>storage</code> プロパティへ直接値をセットする方式です。以下は "test" という文字列を保存した後、値を取り出す例です。</p>
<pre lang="JavaScript">
simpleStorage.storage = "test";
console.log(simpleStorage.storage);	<span class="code-comment">// test</span>
</pre>
<p>文字列だけでなく、数値、配列、オブジェクトなどをセットして保存可能です。</p>
<pre lang="JavaScript">
simpleStorage.storage = { "foo": 100, "bar": 200 };
console.log(simpleStorage.storage.foo);	<span class="code-comment">// 100</span>
</pre>
<p>上記は以下のように書くことも可能です。</p>
<pre lang="JavaScript">
simpleStorage.storage.foo = 100;
simpleStorage.storage.bar = 200;
</pre>
<h4>データの保存先</h4>
<p>Simple Storage APIを使って保存したデータは、プロファイルフォルダ配下の jetpack\{パッケージマニフェストのID}\simple-storage\store.json へJSON形式で保存されます。また、ファイルへの出力タイミングは Jetpack SDK 0.5 時点では Firefox 終了時のみですが、将来的には Firefox 使用中も最大で5分に1回出力される仕様となるようです。</p>
<h4>データ保存可能サイズ</h4>
<p>ひとつの拡張機能が保存できるデータサイズは5MBまでとなっています。 Simple Storage API の <code>quotaUsage</code> プロパティにて現在のデータ使用量（5MBを1.0とした割合）を調べたり、 <code>onOverQuota</code> プロパティにてデータ使用量が最大値を超過したときのコールバック処理を追加したりすることも可能です。ただし、 Jetpack SDK 0.5 時点では正常に動作しないようです。</p>
<pre lang="JavaScript">
console.log(simpleStorage.quotaUsage);
simpleStorage.onOverQuota = function() {
    <span class="code-comment">// データ使用量が最大値を超過したときのコールバック処理</span>
};
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.xuldev.org/blog/?feed=rss2&amp;p=783</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jetpack SDK 0.4 の Widget と Private Browsing API 使用例</title>
		<link>http://www.xuldev.org/blog/?p=735</link>
		<comments>http://www.xuldev.org/blog/?p=735#comments</comments>
		<pubDate>Tue, 08 Jun 2010 16:16:45 +0000</pubDate>
		<dc:creator>Gomita</dc:creator>
				<category><![CDATA[Jetpack]]></category>
		<category><![CDATA[SDK]]></category>

		<guid isPermaLink="false">http://www.xuldev.org/blog/?p=735</guid>
		<description><![CDATA[この記事では、 Jetpack 0.4 で新たに追加された4つの標準APIのうち、 Widget と Private Browsing を使用して実際に機能を開発する手順を解説します。なお、解説はメインプログラムの作成手順以降となります。 Jetpack SDK 自体の基本的な使い方については、 はじめての Jetpack SDK 0.2 を参照してください。 完成イメージ プライベートブラウジングを開始／停止するためのボタンを有する Jetpack 拡張機能を、以下のように3段階に分けて実装します。 フェーズ1: Widget API を使ってUIを追加する フェーズ2: Private Browsing API を使ってボタン押下時にプライベートブラウジングを開始／停止する フェーズ3: Simple Dialog API （自作ライブラリ）を使ってプライベートブラウジング停止確認ダイアログを表示する フェーズ1: Widget API を使ってUIを追加する 一般的な拡張機能では Firefox のメニューバー、ツールバー、ステータスバーなど様々な箇所にUIを追加することが可能で、それゆえUIの一貫性が保たれなくなる問題があります。 Jetpack では Widget API を使ってUIを追加することで、すべての拡張機能のUIの一貫性が保たれるようになります。現在のところ、 Widget API ではステータスバー上部に現れる拡張機能専用のぶっといバーにボタン型UIが追加可能ですが、このUI仕様は今後変更される予定です（参考）。 フェーズ1では、 Widget API を使って非常に単純なボタン型UIを追加します。まず、 main.js [...]]]></description>
			<content:encoded><![CDATA[<p>この記事では、 Jetpack 0.4 で新たに追加された4つの標準APIのうち、 <a href="https://jetpack.mozillalabs.com/sdk/0.4/docs/#module/jetpack-core/widget">Widget</a> と <a href="https://jetpack.mozillalabs.com/sdk/0.4/docs/#module/jetpack-core/private-browsing">Private Browsing</a> を使用して実際に機能を開発する手順を解説します。なお、解説はメインプログラムの作成手順以降となります。 Jetpack SDK 自体の基本的な使い方については、 <a href="./?p=513">はじめての Jetpack SDK 0.2</a> を参照してください。</p>
<h4>完成イメージ</h4>
<p>プライベートブラウジングを開始／停止するためのボタンを有する Jetpack 拡張機能を、以下のように3段階に分けて実装します。</p>
<ul>
<li>フェーズ1: Widget API を使ってUIを追加する</li>
<li>フェーズ2: Private Browsing API を使ってボタン押下時にプライベートブラウジングを開始／停止する</li>
<li>フェーズ3: Simple Dialog API （自作ライブラリ）を使ってプライベートブラウジング停止確認ダイアログを表示する</li>
</ul>
<table class="layout">
<tr>
<td><img src="../misc/wp/jetpack-private-browsing-1.png" width="200" height="100" alt="" /></td>
<td><img src="../misc/wp/jetpack-private-browsing-2.png" width="326" height="121" alt="" /></td>
</tr>
</table>
<h4>フェーズ1: Widget API を使ってUIを追加する</h4>
<p>一般的な拡張機能では Firefox のメニューバー、ツールバー、ステータスバーなど様々な箇所にUIを追加することが可能で、それゆえUIの一貫性が保たれなくなる問題があります。 Jetpack では Widget API を使ってUIを追加することで、すべての拡張機能のUIの一貫性が保たれるようになります。現在のところ、 Widget API ではステータスバー上部に現れる拡張機能専用のぶっといバーにボタン型UIが追加可能ですが、このUI仕様は今後変更される予定です（<a href="http://mozillalabs.com/jetpack/2010/04/08/the-single-ui-element/">参考</a>）。</p>
<p>フェーズ1では、 Widget API を使って非常に単純なボタン型UIを追加します。まず、 main.js 内に以下のように記述して Widget API のモジュールを読み込みます。</p>
<pre lang="JavaScript">
const widgets = require("widget");
</pre>
<p>引き続き main.js へ以下のような main 関数を記述します。</p>
<pre lang="JavaScript">
exports.main = function(options, callbacks) {
	var button = widgets.Widget({
		label: "Start/Stop Private Browsing",
		image: "chrome://browser/skin/Privacy-48.png",
		onClick: function(event) {
			<span class="code-comment">// ToDo</span>
		}
	});
	widgets.add(button);
};
</pre>
<p>はじめに Widget API の <code>Widget(<em>options</em>)</code> コンストラクタを用いてボタンのインスタンスを生成します。コンストラクタの引数 <em>options</em> には下記の3つのプロパティを指定します。</p>
<table class="list">
<tr>
<th>プロパティ</th>
<th>詳細</th>
</tr>
<tr>
<td><code>label</code></td>
<td>ボタンに対する説明の文言。画面に表示されないが、アクセシビリティの観点から指定が必要。</td>
</tr>
<tr>
<td><code>image</code></td>
<td>ボタンのアイコン画像のURL。アイコン画像は24x24ピクセルにリサイズされる。</td>
</tr>
<tr>
<td><code>onClick</code></td>
<td>ボタン押下時に実行するコールバック関数。</td>
</tr>
</table>
<p>なお、 <code>content</code> プロパティに HTML をセットすることで、単純なボタンではなく凝ったUIを作ることも可能です（<a href="http://mozillalabs.com/jetpack/2010/06/02/jetpack-0-4-extension-example-mailping">参考</a>）。</p>
<p>生成したボタンのインスタンスは、 Widget API の <code>add</code> メソッドを用いて実際に追加します。ここまでで、ひとまず「cfx run -a firefox」コマンドで動作確認し、ボタンが表示されることを確認してください。なお、ボタンが配置されるバーは Ctrl+Shift+U で表示／非表示可能です。</p>
<h4>フェーズ2: Private Browsing API を使ってボタン押下時にプライベートブラウジングを開始／停止する</h4>
<p>フェーズ2では、 Private Browsing API を使ってボタン押下時にプライベートブラウジングを開始／停止できるようにします。はじめに main.js の冒頭部分に以下の内容を追加し、 Private Browsing API モジュールを読み込みます。</p>
<pre lang="JavaScript">
const privateBrowsing = require("private-browsing");
</pre>
<p>さらに、 <code>Widget(<em>options</em>)</code> コンストラクタの <code>onClick</code> オプションを以下のように修正します。</p>
<pre lang="JavaScript">
		onClick: function(event) {
			privateBrowsing.active = !privateBrowsing.active;
		}
</pre>
<p>Private Browsing API の <code>active</code> プロパティは真偽値で、現在プライベートブラウジング中かどうかを調べたり、値を変更することでプライベートブラウジングを開始／停止することができます。</p>
<h4>フェーズ3: Simple Dialog API を使ってプライベートブラウジング停止確認ダイアログを表示する</h4>
<p>Private Browsing API にはプライベートブラウジング開始／停止の直前／直後に呼び出すコールバック関数を追加／削除するためのメソッドが用意されています。フェーズ3では、プライベートブラウジング停止直前に確認ダイアログを表示する機能を実装します。</p>
<p>まず、 main.js の冒頭部分に以下の内容を追加し、自作ライブラリである Simple Dialog API モジュールを読み込みます。</p>
<pre lang="JavaScript">
const simpleDialog = require("simple-dialog");
</pre>
<p>Simple Dialog API の詳細は <a href="http://www.xuldev.org/blog/?p=513">はじめての Jetpack SDK 0.2</a> の「自作ライブラリの作成」の項を参照してください。記載されているソースコードをコピペして main.js と同一フォルダ内に「simple-dialog.js」として格納してください。</p>
<p>次に、 main 関数内の最後に以下の内容を追加します。</p>
<pre lang="JavaScript">
	privateBrowsing.onBeforeStop = function(cancel) {
		var yes = simpleDialog.confirmYesNo("Do you want to stop private browsing?");
		if (!yes)
			cancel();
	};
</pre>
<p>Private Browsing API の <code>onBeforeStop</code> プロパティへ、プライベートブラウジング停止直前に呼び出されるコールバック関数をセットします。コールバック関数内では Simple Dialog API の <code>confirmYesNo</code> メソッドを使って確認メッセージを表示し、ユーザが「いいえ」ボタンを押したらコールバック関数の引数 <code>cancel</code> を実行し、停止処理をキャンセルします。</p>
<p>なお、 <code>onBeforeStop.add(<em>callback</em>)</code> メソッドを使ってコールバック関数 <em>callback</em> を追加したり、 <code>onBeforeStop.add([<em>callback1</em>, <em>callback2</em>, ...])</code> のようにして複数のコールバック関数を一括して追加することも可能です。</p>
<h4>動作確認</h4>
<p>ボタンを押下することで、プライベートブラウジングが開始／停止されることを確認してください。また、停止直前に停止確認ダイアログが表示され、「いいえ」ボタンを押下するとプライベートブラウジングが停止されないことを確認してください。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuldev.org/blog/?feed=rss2&amp;p=735</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jetpack SDK 0.4 でのパッケージマニフェストの id プロパティの仕様変更</title>
		<link>http://www.xuldev.org/blog/?p=713</link>
		<comments>http://www.xuldev.org/blog/?p=713#comments</comments>
		<pubDate>Sun, 06 Jun 2010 15:37:56 +0000</pubDate>
		<dc:creator>Gomita</dc:creator>
				<category><![CDATA[Jetpack]]></category>
		<category><![CDATA[SDK]]></category>

		<guid isPermaLink="false">http://www.xuldev.org/blog/?p=713</guid>
		<description><![CDATA[Jetpack SDK 0.4 ではパッケージマニフェスト（package.json）の id プロパティに関する仕様変更があり、自分で決めたIDを明示的に記述することができなくなり、代わりにSDKによって自動生成されるようになりました。 SDK 0.3 以前の仕様 SDK 0.3 以前のバージョンでは、 id プロパティの取り扱いについて以下2通りの方式がありました。 方式1: 明示的に記述する hello-world@xuldev.org のようにメールアドレス形式のIDを自分で決めて、パッケージマニフェスト中に id プロパティとして明示的に記述する方式です。「cfx xpi」コマンドによってXPIインストーラを生成すると、この id プロパティが拡張機能のインストールマニフェストの &#60;em:id&#62; タグの値になります。今まで一般的な拡張機能を開発したことがある方であればこちらの方式のほうが馴染み易いと思います。 方式2: SDKで自動生成する パッケージマニフェストには id プロパティを記述せず、SDKによってIDを自動生成する方式です。「cfx xpi」コマンドでXPIインストーラを生成すると、SDKによって自動的にIDが生成され、XPIインストーラ中のインストールマニフェストの &#60;em:id&#62; タグの値となります。この方式ですと、XPIインストーラを生成するたびに毎回異なるIDが自動生成されるため、新しいバージョンを作って Firefox へインストールするたびに別物の拡張機能としてインストールされてしまう問題がありました。 SDK 0.4 での仕様 SDK 0.4 以降では、 SDK 0.3 以前での方式1のように自分で決めたIDを明示的に記述することはできなくなり、IDはSDKで自動生成された公開鍵・秘密鍵のペアとして管理されるようになりました。 これまで方式1のようにパッケージマニフェスト中に自分で決めたIDを id プロパティとして記述していた場合、いったん id プロパティを削除してください。 id プロパティが記述されていない状態で、SDKで「cfx run」または「cfx xpi」コマンドを実行すると、以下のようなメッセージとともにIDが自動生成されてパッケージマニフェストに id プロパティの記述が追加されます。 [...]]]></description>
			<content:encoded><![CDATA[<p>Jetpack SDK 0.4 ではパッケージマニフェスト（package.json）の id プロパティに関する仕様変更があり、自分で決めたIDを明示的に記述することができなくなり、代わりにSDKによって自動生成されるようになりました。</p>
<h4>SDK 0.3 以前の仕様</h4>
<p>SDK 0.3 以前のバージョンでは、 id プロパティの取り扱いについて以下2通りの方式がありました。</p>
<h5>方式1: 明示的に記述する</h5>
<p><em>hello-world@xuldev.org</em> のようにメールアドレス形式のIDを自分で決めて、パッケージマニフェスト中に id プロパティとして明示的に記述する方式です。「cfx xpi」コマンドによってXPIインストーラを生成すると、この id プロパティが拡張機能のインストールマニフェストの <code>&lt;em:id&gt;</code> タグの値になります。今まで一般的な拡張機能を開発したことがある方であればこちらの方式のほうが馴染み易いと思います。</p>
<h5>方式2: SDKで自動生成する</h5>
<p>パッケージマニフェストには id プロパティを記述せず、SDKによってIDを自動生成する方式です。「cfx xpi」コマンドでXPIインストーラを生成すると、SDKによって自動的にIDが生成され、XPIインストーラ中のインストールマニフェストの <code>&lt;em:id&gt;</code> タグの値となります。この方式ですと、XPIインストーラを生成するたびに毎回異なるIDが自動生成されるため、新しいバージョンを作って Firefox へインストールするたびに別物の拡張機能としてインストールされてしまう問題がありました。</p>
<h4>SDK 0.4 での仕様</h4>
<p>SDK 0.4 以降では、 SDK 0.3 以前での方式1のように自分で決めたIDを明示的に記述することはできなくなり、IDはSDKで自動生成された公開鍵・秘密鍵のペアとして管理されるようになりました。</p>
<p>これまで方式1のようにパッケージマニフェスト中に自分で決めたIDを id プロパティとして記述していた場合、いったん id プロパティを削除してください。 id プロパティが記述されていない状態で、SDKで「cfx run」または「cfx xpi」コマンドを実行すると、以下のようなメッセージとともにIDが自動生成されてパッケージマニフェストに id プロパティの記述が追加されます。</p>
<pre lang="ini">
No 'id' in package.json: creating a new keypair for you.
package.json modified: please re-run 'cfx run'
</pre>
<p>また、このとき、「~/.jetpack/keys/」（Windows の場合「%USERPROFILE%\.jetpack\keys」）配下に、自動生成されたIDに対応する公開鍵・秘密鍵のペアなどが記述されたファイルが生成されます。</p>
<p>再度「cfx run」または「cfx xpi」を実行すると、今度は普通に起動またはXPIインストーラが生成されます。</p>
<h4>複数のPCで開発する場合</h4>
<p>SDK 0.4 では、パッケージのソースファイルを丸ごと別のPCへコピーしてから「cfx run」や「cfx xpi」コマンドを実行するとエラーとなります。もしあなたがそのパッケージの正規開発者ならば、前述の公開鍵・秘密鍵のペアなどが記述されたファイルも一緒にコピーして適切なディレクトリへ配置する必要があります。もしあなたがそのパッケージの派生版を開発しようとしているのならば、パッケージマニフェストの id プロパティを削除して再度SDKによって自動生成する必要があります。このような仕組みによって、そのパッケージが正当な開発者によって作られたものであることが Firefox 側で検証可能となります。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuldev.org/blog/?feed=rss2&amp;p=713</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Jetpack SDK 0.4 で cfx コマンドのユーザ定義オプションを設定する</title>
		<link>http://www.xuldev.org/blog/?p=697</link>
		<comments>http://www.xuldev.org/blog/?p=697#comments</comments>
		<pubDate>Sun, 06 Jun 2010 08:23:12 +0000</pubDate>
		<dc:creator>Gomita</dc:creator>
				<category><![CDATA[Jetpack]]></category>
		<category><![CDATA[SDK]]></category>

		<guid isPermaLink="false">http://www.xuldev.org/blog/?p=697</guid>
		<description><![CDATA[Jetpack SDK 0.4 では、 cfx コマンド実行時に頻繁に使うオプションをあらかじめ local.json に記述しておき、 cfx コマンド実行時に簡単に呼び出すことが可能となりました。 cfx run のオプション Jetpack SDK では、拡張機能を動作確認するときに「cfx run」コマンドを用いますが、このとき、通常のインストール先とは異なる Firefox を起動して実行したい場合に「-b」オプションを付加したり、指定したプロファイルから起動したい場合「-P」オプションを付加します。以下は testuser というプロファイルで Firefox 3.7 上で拡張機能の動作確認をする例です。 cfx run -a firefox -b "%ProgramFiles%\Mozilla Firefox 3.7\firefox.exe" -P "%appdata%\Mozilla\Firefox\Profiles\testuser" cfx コマンドのユーザ定義オプション 前述のような長いオプションを毎回入力するのは面倒です。そこで、 Jetpack SDK 0.4 で導入された local.json に頻繁に使用するオプションを記述しておくと、 cfx コマンドから簡単に呼び出し可能となります。まず、 SDK の展開先フォルダ直下に local.json というファイルを作成し、下記のような内容を記述します。 { "configs": { "ff37": [ "-a", [...]]]></description>
			<content:encoded><![CDATA[<p>Jetpack SDK 0.4 では、 cfx コマンド実行時に頻繁に使うオプションをあらかじめ local.json に記述しておき、 cfx コマンド実行時に簡単に呼び出すことが可能となりました。</p>
<h4>cfx run のオプション</h4>
<p>Jetpack SDK では、拡張機能を動作確認するときに「cfx run」コマンドを用いますが、このとき、通常のインストール先とは異なる Firefox を起動して実行したい場合に「-b」オプションを付加したり、指定したプロファイルから起動したい場合「-P」オプションを付加します。以下は testuser というプロファイルで Firefox 3.7 上で拡張機能の動作確認をする例です。</p>
<pre lang="ini">
cfx run -a firefox -b "%ProgramFiles%\Mozilla Firefox 3.7\firefox.exe" -P "%appdata%\Mozilla\Firefox\Profiles\testuser"
</pre>
<h4>cfx コマンドのユーザ定義オプション</h4>
<p>前述のような長いオプションを毎回入力するのは面倒です。そこで、 Jetpack SDK 0.4 で導入された local.json に頻繁に使用するオプションを記述しておくと、 cfx コマンドから簡単に呼び出し可能となります。まず、 SDK の展開先フォルダ直下に local.json というファイルを作成し、下記のような内容を記述します。</p>
<pre lang="JavaScript">
{
  "configs": {
    "ff37": [
      "-a", "firefox",
      "-b", "C:\\Program Files\\Mozilla Firefox 3.7\\firefox.exe",
      "-P", "C:\\Users\\admin\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\testuser"
    ]
  }
}
</pre>
<p>すると、 cfx コマンドの <code>--use-config</code> オプションにより local.json に記載した <em>ff37</em> という名前のユーザ定義オプションが有効になります。 <code>--use-config=ff37</code> の代わりに <code>-g ff37</code> としても構いません。</p>
<pre lang="ini">
cfx run --use-config==ff37
</pre>
<p>もちろん cfx run だけでなく cfx xpi などでも同様の方式で local.json に定義したオプションを呼び出し可能です。なお、 local.json 内ではバックスラッシュを「\\」とエスケープすること、また Windows の環境変数は使用できないことにご注意ください。</p>
<h4>cfx コマンドのデフォルトオプション</h4>
<p><em>default</em> という名前のユーザ定義オプションを記述すると、これは <code>--use-config</code> オプション未指定時のデフォルトオプションとして自動的に呼び出されます。例えば、 local.json へ以下のように記述を追加します。</p>
<pre lang="JavaScript">
{
  "configs": {
    "default": [
      "-a", "firefox",
      "-P", "C:\\Users\\admin\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\testuser"
    ],
    "ff37": [
      "-a", "firefox",
      "-b", "C:\\Program Files\\Mozilla Firefox 3.7\\firefox.exe",
      "-P", "C:\\Users\\admin\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\testuser"
    ]
  }
}
</pre>
<p>すると、単に <code>cfx run</code> などを実行したとき、設定名 <em>default</em> で定義したデフォルトオプションが有効となります。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuldev.org/blog/?feed=rss2&amp;p=697</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XPCOM サービスへの頻繁なアクセスを効率化するテクニック</title>
		<link>http://www.xuldev.org/blog/?p=566</link>
		<comments>http://www.xuldev.org/blog/?p=566#comments</comments>
		<pubDate>Sun, 09 May 2010 05:21:54 +0000</pubDate>
		<dc:creator>Gomita</dc:creator>
				<category><![CDATA[XPCOM]]></category>

		<guid isPermaLink="false">http://www.xuldev.org/blog/?p=566</guid>
		<description><![CDATA[拡張機能や XUL アプリにて、 JavaScript から特定の XPCOM サービスを頻繁に使用するケースがよくあります。そのような場合に処理やソースコードを効率化するためのテクニックをいくつか紹介します。ここでは、例として nsIObserverService を頻繁に利用するケースを想定します。なお、Cc は Components.classes, Ci は Components.interfaces への参照です。 方式1: 毎回 XPCOM サービスを呼び出す 特に工夫をしない場合、以下のように XPCOM サービスを利用するたびに毎回そのスコープ内で呼び出し手続きを行うことになります。 var MyExtension = { init: function() { var observerSvc = Cc["@mozilla.org/observer-service;1"]. getService(Ci.nsIObserverService); observerSvc.addObserver(...); }, uninit: function() { var observerSvc = Cc["@mozilla.org/observer-service;1"]. getService(Ci.nsIObserverService); observerSvc.removeObserver(...); }, }; 方式2: グローバル変数として定義 最初に XPCOM サービスの呼び出しを行い、グローバル変数 gObserverSvc として参照を保持します。 この方式ですと、スクリプトロード直後（実際に [...]]]></description>
			<content:encoded><![CDATA[<p>拡張機能や XUL アプリにて、 JavaScript から特定の XPCOM サービスを頻繁に使用するケースがよくあります。そのような場合に処理やソースコードを効率化するためのテクニックをいくつか紹介します。ここでは、例として nsIObserverService を頻繁に利用するケースを想定します。なお、<code>Cc</code> は <code>Components.classes</code>, <code>Ci</code> は <code>Components.interfaces</code> への参照です。</p>
<h4>方式1: 毎回 XPCOM サービスを呼び出す</h4>
<p>特に工夫をしない場合、以下のように XPCOM サービスを利用するたびに毎回そのスコープ内で呼び出し手続きを行うことになります。</p>
<pre lang="JavaScript">
var MyExtension = {
	init: function() {
		var observerSvc = Cc["@mozilla.org/observer-service;1"].
		                  getService(Ci.nsIObserverService);
		observerSvc.addObserver(...);
	},
	uninit: function() {
		var observerSvc = Cc["@mozilla.org/observer-service;1"].
		                  getService(Ci.nsIObserverService);
		observerSvc.removeObserver(...);
	},
};
</pre>
<h4>方式2: グローバル変数として定義</h4>
<p>最初に XPCOM サービスの呼び出しを行い、グローバル変数 <code>gObserverSvc</code> として参照を保持します。<br />
この方式ですと、スクリプトロード直後（実際に XPCOM サービスを使うタイミングよりも前）に XPCOM サービスの呼び出しが行われます。したがって、その XPCOM サービスを必ずしも使うとは限らないケースには向いていません。</p>
<pre lang="JavaScript">
var gObserverSvc = Cc["@mozilla.org/observer-service;1"].
                   getService(Ci.nsIObserverService);

var MyExtension = {
	init: function() {
		gObserverSvc.addObserver(...);
	},
	uninit: function() {
		gObserverSvc.removeObserver(...);
	},
};
</pre>
<h4>方式3: 拡張機能専用オブジェクトのプロパティとして定義</h4>
<p>グローバル変数として定義せずに、拡張機能専用オブジェクト <code>MyExtension</code> の <code>observerSvc</code> プロパティとして定義します。<br />
この方式ですと、実際に XPCOM サービスを使うタイミング（<code>observerSvc</code> プロパティを参照した時）に XPCOM サービスの呼び出しが行われます。逆に、その XPCOM サービスを使わない場合は無駄に XPCOM サービスの呼び出しが行われることがない、という利点があります。</p>
<pre lang="JavaScript">
var MyExtension = {
	get observerSvc() {
		return Cc["@mozilla.org/observer-service;1"].
		       getService(Ci.nsIObserverService);
	},
	init: function() {
		this.observerSvc.addObserver(...);
	},
	uninit: function() {
		this.observerSvc.removeObserver(...);
	},
};
</pre>
<h4>方式4: 一度取得した参照をキャッシュ</h4>
<p>方式3は、XPCOM サービスを使う（<code>observerSvc</code> プロパティを参照する）たびに毎回 XPCOM サービスの呼び出しが行われるという欠点があります。一方、こちらの方式4では、 <code>observerSvc</code> プロパティが初めて参照された際に、取得した XPCOMサービスへの参照を <code>_observerSvc</code> プロパティ（先頭にアンダーバー付きのプライベート的なプロパティ）として保持し、二回目以降のサービス使用時は保持した参照を返します。</p>
<pre lang="JavaScript">
var MyExtension = {
	_observerSvc: null,
	get observerSvc() {
		if (!this._observerSvc) {
			this._observerSvc = Cc["@mozilla.org/observer-service;1"].
			                    getService(Ci.nsIObserverService);
		}
		return this._observerSvc;
	},
	init: function() {
		this.observerSvc.addObserver(...);
	},
	uninit: function() {
		this.observerSvc.removeObserver(...);
	},
};
</pre>
<h4>方式5: 一度取得した参照をキャッシュ（改良版）</h4>
<p>方式4をさらに改良し、プロパティの数を節約したバージョンです。<br />
<code>observerSvc</code> プロパティへの初回参照時に、プロパティ自身を XPCOM サービスへの参照へと置き換えます。<br />
<code>return a = b;</code> という書き方により、 <code>a</code> に <code>b</code> を代入して、さらに <code>a</code> の値を返します。</p>
<pre lang="JavaScript">
var MyExtension = {
	get observerSvc() {
		delete this.observerSvc;
		return this.observerSvc = Cc["@mozilla.org/observer-service;1"].
		                          getService(Ci.nsIObserverService);
	},
	init: function() {
		this.observerSvc.addObserver(...);
	},
	uninit: function() {
		this.observerSvc.removeObserver(...);
	},
};
</pre>
<h4>方式6: 一度取得した参照をキャッシュ（クラス対応）</h4>
<p>方式5のような単独のオブジェクトではなく、クラスのプロパティとする場合、理由はよくわかりませんが以下のように書く必要があるようです。</p>
<pre lang="JavaScript">
function MyExtensionClass() { ... }

MyExtensionClass.prototype = {
	get observerSvc() {
		var svc = Cc["@mozilla.org/observer-service;1"].
		          getService(Ci.nsIObserverService);
		this.__defineGetter__("observerSvc", function() svc);
		return svc;
	},
	init: function() {
		this.observerSvc.addObserver(...);
	},
	uninit: function() {
		this.observerSvc.removeObserver(...);
	},
};
</pre>
<h4>方式7: XPCOMUtils.defineLazyServiceGetter を使う</h4>
<p><a href="https://developer.mozilla.org/en/JavaScript_code_modules/XPCOMUtils.jsm">XPCOMUtils.jsm</a> という標準の JavaScript モジュールをインポートすると、方式5は以下のように defineLazyServiceGetter を使って書くことができます。ただし方式7は Firefox 3.6 (Gecko 1.9.2) 以降限定です。また、 browser.xul 内であれば Firefox 本体側ですでにモジュールがインポート済みなので、拡張機能側で改めてインポートする必要はありません。</p>
<pre lang="JavaScript">
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");

var MyExtension = {
	init: function() {
		this.observerSvc.addObserver(...);
	},
	uninit: function() {
		this.observerSvc.removeObserver(...);
	},
};

XPCOMUtils.defineLazyServiceGetter(
	MyExtension, "observerSvc", "@mozilla.org/observer-service;1", "nsIObserverService"
);
</pre>
<h4>方式8: Services.jsm を使う</h4>
<p><a href="https://developer.mozilla.org/en/JavaScript_code_modules/Services.jsm">Services.jsm</a> という標準の JavaScript モジュールをインポートすると、ごく一部の XPCOM サービスへの参照を手軽に取得できます。  nsIObserverService であれば <code>Services.obs</code> で参照できます。実は Services.jsm モジュール内部では XPCOMUtils.defineLazyServiceGetter が使用されており、また、すべての拡張機能および Firefox 本体でシングルトンの参照を保持できるという JavaScript モジュールの特性を考えると、最も効率的な方式といえるでしょう。ただし方式8は Firefox 3.7 (Gecko 1.9.3) 以降限定です。また、 browser.xul 内であれば Firefox 本体側ですでにモジュールがインポート済みなので、拡張機能側で改めてインポートする必要はありません。</p>
<pre lang="JavaScript">
Components.utils.import("resource://gre/modules/Services.jsm");

var MyExtension = {
	init: function() {
		Services.obs.addObserver(...);
	},
	uninit: function() {
		Services.obs.removeObserver(...);
	},
};
</pre>
<h4>方式9: 独自モジュール内で定義する</h4>
<p>方式8に近いですが、拡張機能独自の JavaScript モジュールを作り、頻繁にアクセスする XPCOM サービスへの参照はそのモジュールのプロパティとして定義（その際に方式5や方式7を利用）してしまう手もあります。たくさんの XUL ウィンドウから XPCOM サービスへアクセスするような規模の大きい拡張機能に向いています。<br />
また、そもそも拡張機能のメインプログラムがモジュール化されている場合は、そのモジュール内で方式5や方式7を使ってキャッシュを行うことで効率化が可能です。</p>
<h4>私見</h4>
<p>個人的には多くの場合は方式5で、グローバル変数を増やしても他への影響が少ない拡張機能独自のウィンドウ内で、それほど効率化を意識する必要の無い場面や単に面倒な場合は方式2、という感じです。最近の Firefox 本体のソースコードを見ると方式7,8が主流となりつつあるようですが、古いバージョンの Firefox にも対応しなければならない拡張機能としては、今のところは対応する Firefox のバージョンが限られてしまうのが難点です。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuldev.org/blog/?feed=rss2&amp;p=566</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
