このサイトの記事更新は2019年11月に終了されました。過去記事アーカイブを公開しています。

投稿されたすべてのトピック

Mozilla 勉強会@北海道の資料を公開しています

先週末、OSC 北海道の中で Mozilla 勉強会@北海道 を開催しました。暑い中ご参加いただき、ありがとうございました。スライドやデモなどの資料は上のリンクからご覧いただけます。

私が担当したセッション「イチから始める Firefox 拡張機能開発」の資料は ZIP ファイル でダウンロードできます。プレゼン (PDF) には関連リンクも含まれていますので、適宜参照してください。また modest 内の 拡張機能開発入門 にも各種ドキュメントへのリンクが載っています。

当日デモに使った「天気はどう?」拡張機能は tenkiwado.xpi というファイルです。Firefox のウィンドウ内にドラッグ&ドロップすれば直接インストールできますし、これは実際には ZIP ファイルなので、拡張子を変えれば展開してソースコードを見ることができます。JavaScript には詳しいコメントも入れていますので、実際にどういう仕組みで動いているか、参考にしてください。

実はもうひとつ「ニュースはどう?」という拡張機能 newswado.xpi もセッションの直前に作ってありました。これは北海道新聞の速報ニュースをティッカー表示するツールバーです。ソースコードは簡単ですので、同じように展開して見てみてください。

拡張初学者用スケルトン

 AMOアドオンビルダーの作成するスケルトンがあまりに酷いのでごくシンプルなスケルトンを作成しました。
 大元はAMOアドオンビルダが作成するスケルトンですが以下のものを省きました。

  • ローカライズの処理
  • 呼び出されることのないイベント・ハンドラ
  • アクセス不能なオブジェクト
  • 初学者には敷居の高い XPCOM コンポーネントの呼び出し

 また、若干ですが Firefox にオーバーレイするXULファイル、ならびにファイル構成も簡素化しています。ただし、このスケルトンでは使っていない local、skin のディレクトリはそのまま残しています。

 再利用される場合は、他の拡張とコンフリクトを起こさないように修正してください。

/wp-content/uploads/2010/06/skeleton.zip

 以上の説明で用語や概念等について解からないこともあるかと思いますので、その場合はFirefox拡張機能開発チュートリアルを参照してください。

JSMをimportしているコード内のfunctionをJSM側から呼び出すには

みなさんは JavaScript Code Module ( 以下 JSM と略記します ) を書いていて、その JSM を import するコード側の function を JSM 側からコールしたい、といったニーズが発生したことはないでしょうか。
つまり以下のようなことをしたいケースです。

// hoge.jsm 側のコード
function hoge(){
		...
	changeXUL(); // JSM を import する側で定義されている function
		...
};
//JSM を import する側のコード
{
	Components.utils.import("resource://hoge/hoge.jsm",scopeHoge);
	let changeXUL=function(){ // JSM 側から呼び出したい function
		...
		// ブラウザの要素を DOM で変更する処理など
		...
	};
		...
}

上記コードはこのままでは動きません。hoge() 内でコールされている changeXUL() が undefined となります。
しかし hoge() から changeXUL() をコールしたいケースがないわけではありません。ここでは hoge() から changeXUL() をコールする方法を解説します。


上記の方法では hoge() から changeXUL() をコールできないことは先に述べました。hoge() から changeXUL() を呼び出すには、changeXUL() への参照を JSM 側に持つことで解決します。

最初に JSM 側に changeXUL() への参照を格納する変数を定義します。

var funcCallback;

同じく JSM 側に変数 funcCallback に changeXUL() への参照を設定する setter を定義します。

var EXPORTED_SYMBOLS=[
	"setCallback"
];
		...
function setCallback(pfunc){
	funcCallback=pfunc;
}

今度は JSM を import するコード側であらかじめ先の setter をコールするコードを書いておきます。

{
	let scopeHoge={};
	Components.utils.import("resource://hoge/hoge.jsm",scopeHoge);
		...
	let changeXUL=function(){ // JSM 側から呼び出したい function
		...
		// ブラウザの要素を DOM で変更する処理など
		...
	};
		...
	let init(){
		scopeHoge.setCallback(changeXUL); // setter のコール
	};
}

更に本来は hoge() 内に書きたかった changeXUL() の代りに changeXUL() への参照 funcCallback を書いてやります。

// hoge.jsm 側のコード
function hoge(){
		...
	funcCallback(); // changeXUL() への参照の呼び出し
		...
}

後は JSM 側で hoge() がコールされれば、changeXUL() への参照である funcCallback を通して changeXUL() のコードが実行されます。

以上のコードを整理して記述すると以下のようになります。

// hoge.jsm
var EXPORTED_SYMBOLS=[
	"setCallback"
];
var funcCallback;
		...
function setCallback(pfunc){
	funcCallback=pfunc;
}
		...
function hoge(){
		...
	funcCallback(); // changeXUL() への参照の呼び出し
		...
}
// hoge.jsm を import する側
{
	let scopeHoge={};
	Components.utils.import("resource://hoge/hoge.jsm",scopeHoge);
		...
	let changeXUL=function(){ // JSM 側から呼び出したい function
		...
		// ブラウザの要素を DOM で変更する処理など
		...
	};
		...
	let init(){
		scopeHoge.setCallback(changeXUL); // setter のコール
	};
}

以上の方法のなにが嬉しいのかといいますと、私の場合であれば JSM 内で XMLHttpRequest を非同期で利用する際、コールバック内でブラウザの要素を書き換えたい場合等に利用しています。

フォク蔵を ‘How to Improve Extension Startup Performance‘ に対応させるのに、この手法を利用しています。MPL、GPL、LGPL のトリプルライセンスでソースを公開していますので、自由に参照してください。


【追記】
dynamis さんが、よりシンプルな方法をコメントしてくださいました。ありがとうございます。
以下は dynamis さんが紹介されている “hoge(… , callback)” のように、コールバック関数を直接 JSM 内の function に引数として渡す方法のサンプルです。

// hoge.jsm
var EXPORTED_SYMBOLS=[
	"hoge"
];

function hoge(pstr,funcCallback){
		...
	funcCallback(pstr); // hoge.jsm を import している側のコードの dispStr() を実行
	                    // 'Hello Hogeヽ(°▽°、)ノ'が表示される
		...
}
{
	// JSM を import する側のコード
	let scopeHoge={};
	Components.utils.import("resource://hoge/hoge.jsm",scopeHoge);
		...
	let dispStr=function(pStr){
		alert(pStr);
	};
		...
	let sampleOrg=function(){
		...
		scopeHoge.hoge('Hello Hogeヽ(°▽°、)ノ', dispStr);
	};
		...
}

原理は最初のものと一緒ですが、ぐっとシンプルになって、コードの見通しも良くなっています。

ちなみに dynamis さんの方法と私の方法の違いは、私の方法は hoge() がJSM を import している側のコードから、ネストも含めて直接呼ばれないことを前提としている点です。
目的に合わせてそれぞれ使い分けるといいかと思います。

JavaScript コードモジュール

拡張機能開発時でよく使う再利用性のあるコードをインポート可能な形で書いたものを JavaScript コードモジュールといいます。コードモジュールは単に再利用できるだけでなく、何度読み込んでも最初の一度だけ初期化されて使い回されるシングルトンになるという特徴があるため、高速に動作する拡張機能開発のベストプラクティスとしても知られています。

コードモジュールは Firefox 3 からサポートされており、これから新規に拡張機能を開発するにあたっては遠慮無く使っていける時期になってきているはずです。みんなでコードモジュールを使って、作って、共有していきたいですね。(・・).

ここではいくつかのコードモジュールを紹介します。他にも公開されているコードモジュールがあれば皆さん随時追記していってください。

Firefox 標準搭載のコードモジュール

Mozilla Labs で開発されているコードモジュール

詳細は https://wiki.mozilla.org/Labs/JS_Modules を参照 。

  • JSON
  • Logging
  • Observers
  • Preferences
    • 環境設定 (prefs) の操作に便利です。型を気にせず一括設定や読み込みできます
  • StringBundle
    • l10n の properties ファイル読み込みが楽になります。xul に bundle 要素書かずに済みますし
  • Sync
  • URI

Mozilla Labs 製の一部のモジュールについては、Firefox Sync または Firefox 4 本体に同梱されています。上記のページにリンクされているものよりも新しいバージョンのモジュールもあるので、 http://hg.mozilla.org/mozilla-central/file/tip/services/sync/modules/ext/ を参照するのもよいかと。

その他のコードモジュール

  • jstimer.jsm – written by Piro さん
    • nsITimer を wrap して使い慣れている setTimeout / setInterval のように使えるようにしたモジュール
  • jquery.js – written by dynamis based on jQuery
    • jQuery を拡張機能の互換性問題など生じずに使えるようにした「つもり」のモジュール
    • animation, mouse event, ajax 周りは使えることを確認済みだが他は未検証
    • jQuery は HTML であり XUL 要素に対して同じ効果を実現できないこともあるハズ
  • console.js – written by dynamis
    • Firebug と連携して Firebug 感覚でデバッグするためのモジュール
    • loglevel の設定、Firebug のコンソールへの出力、dump 出力など
  • namespace.jsm – written by Piro
    • 複数のアドオンにまたがった共通の名前空間を作成するためのモジュール。
  • animationManager.js – written by Piro
    • JavaScriptベースのアニメーション効果を実装する際に、各アドオンで別々にタイマーを走らせずに単一のタイマーで処理を行うためのモジュール。アニメーション効果が軽くなることが期待できる。JavaScriptコードモジュールとして使用する場合はjstimer.jsmに依存し、namespace.jsmとの併用に対応。
  • autoScroll.js – written by Piro
    • ドラッグ操作中におけるタブバーの自動スクロールを実現するためのモジュール。namespace.jsmとの併用に対応。
  • boxObject.js – written by Piro
    • nsIBoxObjectと共通のインターフェースで任意のDOM要素の位置と大きさを取得するモジュール。Geckoから削除された機能であるHTMLDocument.getBoxObjectForを使っていたコードを、最小限の変更で最近のGeckoに対応させるための物。namespace.jsmとの併用に対応。
  • prefs.js – written by Piro
  • stringBundle.js – written by Piro
  • CLHHelper.jsm – written by クリアコード
    • nsICommandLineHandlerインターフェースを備えたXPCOMコンポーネントの開発を支援するモジュール。
  • ejs.jsm – written by クリアコード
  • encoding.jsm – written by クリアコード
    • UTF-8、Shift_JIS、EUC-JPなど、文字列のエンコーディングを変換する処理を簡単に書くためのモジュール。
  • hash.jsm – written by クリアコード
    • 文字列やファイルのハッシュの計算結果を簡単に取得するためのモジュール。
  • action.jsm – written by クリアコード
    • ボタンのクリックやキーの押下など、ユーザの操作をDOMイベントのレベルでエミュレートするためのモジュール。

その他いろいろな拡張機能に独自のコードモジュールが含まれているので色々探してみてください(いいものがあれば紹介を追加してください)。

JavaScript ライブラリ

JavaScript コードモジュール形式になっていないが、便利に使い回せる JavaScript ライブラリです。

  • Piro さんのライブラリ集
    • 拡張機能開発者といえば Piro さん。(^^;
    • 独立性の高いコードになっているので prefs.js を元に冒頭に EXPORTED_SYMBOLS と window だけ定義してコードモジュール化した prefs.js にできるなど、簡単にコードモジュール形式にできるものが多いそうです!→という風な改造を特に施さなくても、コードモジュールとして読み込んでも<script/>で読み込んでも使えるようにしてみました。(by Piro)

references

JavaScript コードモジュールについて詳しい解説は以下のページをご覧ください。

Firefox学生向けアドオンパック、リリース前最終確認ミーティング!

こんにちは!

Firefox学生マーケティングの新メンバーとして、最近加入させて頂いた

玉川大学リベラルアーツ学部の立野です。

みなさん☆

本日6/17(木)に、いよいよ

Firefox学生向けアドオンパック

がリリースされます!

今回のミーティングでは、その最終確認を行い、

このアドオンパックをどのように広報しようかという相談をしました!

チーム名が「Firefox 学生マーケティング」に決定したところで、

マーケティングチームとして、Firefoxをみんなに広めたいという思いも

強くなりました!

学生の方も、学生じゃない方もぜひ

インストールして活用してみてください^^☆

Jetpack SDK 0.4 がリリースされました

10日ほど前のことですが、 Mozilla Labs のブログ で告知されている通り、 Jetpack SDK の新バージョンである 0.4 がリリースされました。

SDK 0.4 では新たに以下の4つのAPIが追加されています。

  • Widget
    Firefox / Thunderbird のウィンドウへ拡張機能専用のボタン型UIを追加するためのAPI。一貫性のあるUI(拡張機能専用のバーに配置されたボタン型UI)によって機能を提供することが可能となります。
  • Page Worker
    不可視の iframe 要素にページを読み込んでDOM操作をするためのAPI。従来の XMLHttpRequest では困難な、 HTMLのDOM操作を必要とするコンテンツとのマッシュアップなどが実現可能となるようです。
  • Simple Storage
    数値、文字列、JSONデータなどを永続的に保持するためのAPI。いわば DOMストレージの拡張機能版です。
  • Private Browsing
    Firefox のプライベートブラウジング機能を開始・停止したり、開始前後・停止前後にコールバック処理を実行したりするためのAPI。

さらに、以下3つの新機能およびSDKの仕様変更があります。

  • Firefox 再起動不要
    Minefield 3.7a5pre であれば、 Jetpack SDK 0.4 で開発した拡張機能を、 Firefox を再起動せずにインストール・アンインストール可能となりました。
  • package.json の id の仕様変更
    package.json の id プロパティの仕様が変更され、 Jetpack SDK により自動的に暗号化ハッシュとして生成されるようになりました。
  • local.json による cfx コマンドのオプション指定
    cfx コマンド実行時に頻繁に使うオプションをあらかじめ local.json に記述しておき、 cfx コマンド実行時に簡単に呼び出し可能となりました。

各APIを使ったサンプルや新機能に関する説明も順次アップしてきます。

SCRAPBLOG : Jetpack SDK 0.4 で cfx コマンドのユーザ定義オプションを設定する
SCRAPBLOG : Jetpack SDK 0.4 でのパッケージマニフェストの id プロパティの仕様変更
SCRAPBLOG : Jetpack SDK 0.4 の Widget と Private Browsing API 使用例
SCRAPBLOG : Jetpack SDK 0.4 の Simple Storage API
SCRAPBLOG : Jetpack SDK 0.4 の Page Worker API

Firefox学生マーケティングを行いました!

はじめまして!

Firefox学生マーケティングに参加させてもらっている
中央大学理工学部の瀬瀬考平です。

昨日の夜、Mozilla Japanのオフィスに大学生が集まって
Mozilla Japanの方とミーティングをしました!

昨日から新メンバーも加わりさらにパワーアップ!!

こんな感じでいつも通り和気あいあいと楽しくやってます!

学生向けアドオンパックの企画もいよいよ大詰めになってきました!

そして、ついに
今月中に学生向けアドオンパックをリリース出来そうになりました!!

※Firefox学生マーケティング、学生向けアドオンパックについては
 先日のMozilla 勉強会@東京 3rd で守山さん佐藤さんが発表した資料をご覧ください。
 http://www.slideshare.net/cou929/firefox-4105604

興味のある大学生の方の参加もお待ちしてます!

MDCの永久保存版を公開しました

Mozilla Developer Centerの永久保存版、localmdc を公開しました。
あわせて、Windowsヘルプ、infoもご用意しました。キーワード検索、テキスト検索で、素早くページを探せます。
modest様に、サーバー資源、回線帯域のご提供をいただいております。大変ありがとうございます。
Happy Hacking!

Firefox 4 の Indexed Database API を先取り紹介

訳注: 本文において IndexedDB と書かれている技術仕様の正式名称は Indexed Database API です。名前にスペースを含めることが議論により決定しています。

localStorage では単純なクライアントサイドのキーと値のペアを保存することができますが、これだけではまだウェブアプリケーションのための構造的でインデックスされたデータストレージの需要を叶えるものではありません。Mozilla では構造的ストレージとインデックスのための API である IndexedDB をサポートし、数週間以内にテストビルドをリリースする予定です。IndexedDB は、WebDatabase API という、SQLite のサブセット言語を用いる、いくつかのブラウザに実装されている API と比較することができます。Mozilla はこちらのポストに書かれているいくつかの理由により WebDatabase をサポートしないことを決定しています。

訳注: この経緯は「ブラウザ上のデータベースに関して」という記事に詳しいです。

IndexedDB と WebDatabase を比較するために、これらの仕様の非同期 API をほぼ網羅する4つの例を紹介します。これを読むとテーブルのある SQL ストレージ (WebDatabase) とインデックス付き JavaScript オブジェクトストレージ (IndexedDB) の違いがとてもよく分かるでしょう。同期バージョンの API は Worker スレッドからしか使うことができません。Worker スレッドはまだ全てのブラウザでサポートされているわけではないため、ここでは同期 API のことは話しません。IndexedDB のコードは、Mozilla が W3C WebApps ワーキンググループ (WG) に提出し、今のところ良いフィードバックを貰えている提案をベースとしています。両 API のコードは簡単のためにエラー処理などはしていませんが、もちろんみなさんが実用で使うときは忘れないようにしましょう。

訳注: Mozilla の提出した API 改正案はまだ2010年6月1日現在の Indexed Database API 仕様草案には反映されていませんが、Google Chrome チームの数人からの同意もあり、ほぼそのまま採用されると思われます。

キャンディー屋さんとお客さん (kids ということにします) の例を考えてみましょう。candySales という欄は、一人のお客さんへのあるキャンディーの売り上げを表しています。

例 1 – データベースを開いてセットアップする

最初の例は、データベースを開く方法を示します。データベースを開くときにバージョンをチェックし、必要なテーブルやオブジェクトストアを作り、正しい バージョン番号をセットします。WebDatabase はバージョンを厳しく処理し、開こうとしているデータベースのバージョンと違うものだった場合はエラーを出します。IndexedDB は単に呼び出す人がバージョン管理できるようにするだけです。バージョン管理に関してはまだ WG でも議論中なので注意してください。

WebDatabase

var db = window.openDatabase("CandyDB", "",
                             "My candy store database",
                             1024);
if (db.version != "1") {
  db.changeVersion(db.version, "1", function(tx) {
    // はじめてのユーザー。データベースを初期化。
    var tables = [
      { name: "kids", columns: ["id INTEGER PRIMARY KEY",
                                "name TEXT"]},
      { name: "candy", columns: ["id INTEGER PRIMARY KEY",
                                 "name TEXT"]},
      { name: "candySales", columns: ["kidId INTEGER",
                                      "candyId INTEGER",
                                      "date TEXT"]}
    ];
    for (var index = 0; index < tables.length; index++) {
      var table = tables[index];
      tx.executeSql("CREATE TABLE " + table.name + "(" +
                    table.columns.join(", ") + ");");
    }
  }, null, function() { loadData(db); });
}
else {
  // はじめてのユーザーではない。初期化しなくていい。
  loadData(db);
}

IndexedDB

var request = window.indexedDB.open("CandyDB",
                                    "My candy store database");
request.onsuccess = function(event) {
  var db = event.result;
  if (db.version != "1") {
    // はじめてのユーザー。データベースを初期化。
    var createdObjectStoreCount = 0;
    var objectStores = [
      { name: "kids", keyPath: "id", autoIncrement: true },
      { name: "candy", keyPath: "id", autoIncrement: true },
      { name: "candySales", keyPath: "", autoIncrement: true }
    ];

    function objectStoreCreated(event) {
      if (++createdObjectStoreCount == objectStores.length) {
        db.setVersion("1").onsuccess = function(event) {
          loadData(db);
        };
      }
    }

    for (var index = 0; index < objectStores.length; index++) {
      var params = objectStores[index];
      request = db.createObjectStore(params.name, params.keyPath,
                                     params.autoIncrement);
      request.onsuccess = objectStoreCreated;
    }
  }
  else {
    // はじめてのユーザーではない。初期化しなくていい。
    loadData(db);
  }
};

例 2 – お客さんをデータベースに保存する

この例では何人かのお客さんをテーブルやオブジェクトストアに保存します。また、WebDatabase では SQL injection のリスクを処理しなければいけないことを示します。WebDatabase では明示的にトランザクションを使わなければいけませんが、IndexedDB ではトランザクションは、たった一つのオブジェクトストアがアクセスされた場合に自動的に作られます。IndexedDB ではトランザクションのロックはオブジェクトストア毎です。さらに、IndexedDB では JavaScript のオブジェクトを挿入できますが、WebDatabase では特別にコラムを作らなければいけません。どちらの場合もコールバックで挿入 ID を得ることができます。

WebDatabase

var kids = [
  { name: "Anna" },
  { name: "Betty" },
  { name: "Christine" }
];

var db = window.openDatabase("CandyDB", "1",
                             "My candy store database",
                             1024);
db.transaction(function(tx) {
  for (var index = 0; index < kids.length; index++) {
    var kid = kids[index];
    tx.executeSql("INSERT INTO kids (name) VALUES (:name);", [kid],
                  function(tx, results) {
      document.getElementById("display").textContent =
          "Saved record for " + kid.name +
          " with id " + results.insertId;
    });
  }
});

IndexedDB

var kids = [
  { name: "Anna" },
  { name: "Betty" },
  { name: "Christine" }
];

var request = window.indexedDB.open("CandyDB",
                                    "My candy store database");
request.onsuccess = function(event) {
  var objectStore = event.result.objectStore("kids");
  for (var index = 0; index < kids.length; index++) {
    var kid = kids[index];
    objectStore.add(kid).onsuccess = function(event) {
      document.getElementById("display").textContent =
        "Saved record for " + kid.name + " with id " + event.result;
    };
  }
};

例 3 – お客さんの一覧を表示する

この例では kids テーブルと kids オブジェクトストアに保存されたお客さんを表示します。WebDatabase は全部の列を取得した後でコールバックメソッドに result set オブジェクトを渡します。一方、IndexedDB は結果を取得するごとに cursor handler を渡すので、結果が速く返ってくることになります。この例では示されていませんが、cursor.continue() を呼ばないことで繰り返しを止めることができます。

WebDatabase

var db = window.openDatabase("CandyDB", "1",
                             "My candy store database",
                             1024);
db.readTransaction(function(tx) {
  // テーブル全体を検索
  tx.executeSql("SELECT * FROM kids", function(tx, results) {
    var rows = results.rows;
    for (var index = 0; index < rows.length; index++) {
      var item = rows.item(index);
      var element = document.createElement("div");
      element.textContent = item.name;
      document.getElementById("kidList").appendChild(element);
    }
  });
});

IndexedDB

var request = window.indexedDB.open("CandyDB",
                                    "My candy store database");
request.onsuccess = function(event) {
  // オブジェクトストア全体をまわる
  request = event.result.objectStore("kids").openCursor();
  request.onsuccess = function(event) {
    var cursor = event.result;
    // cursor が null なら終了
    if (!cursor) {
      return;
    }
    var element = document.createElement("div");
    element.textContent = cursor.value.name;
    document.getElementById("kidList").appendChild(element);
    cursor.continue();
  };
};

例 4 – キャンディーを買ったお客さんを列挙する

この例ではキャンディーを買ったお客さんと、どれだけのキャンディーを買ったのかを表示します。WebDatabase では単に LEFT JOIN したクエリを使えば簡単にできます。IndexedDB は今のところ別々のオブジェクトストアをまたいだ JOIN をする API がありません。そのため、この例では kids オブジェクトへの cursor と candySales オブジェクトストアの kidId インデックスへのオブジェクト cursor を開き、手動で JOIN をしています。

WebDatabase

var db = window.openDatabase("CandyDB", "1",
                             "My candy store database",
                             1024);
db.readTransaction(function(tx) {
  tx.executeSql("SELECT name, COUNT(candySales.kidId) " +
                "FROM kids " +
                "LEFT JOIN candySales " +
                "ON kids.id = candySales.kidId " +
                "GROUP BY kids.id;",
                function(tx, results) {
    var display = document.getElementById("purchaseList");
    var rows = results.rows;
    for (var index = 0; index < rows.length; index++) {
      var item = rows.item(index);
      display.textContent += ", " + item.name + "bought " +
                             item.count + "pieces";
    }
  });
});

IndexedDB

candyEaters = [];
function displayCandyEaters(event) {
  var display = document.getElementById("purchaseList");
  for (var i in candyEaters) {
    display.textContent += ", " + candyEaters[i].name + "bought " +
                           candyEaters[i].count + "pieces";
  }
};

var request = window.indexedDB.open("CandyDB",
                                    "My candy store database");
request.onsuccess = function(event) {
  var db = event.result;
  var transaction = db.transaction(["kids", "candySales"]);
  transaction.oncomplete = displayCandyEaters;

  var kidCursor;
  var saleCursor;
  var salesLoaded = false;
  var count;

  var kidsStore = transaction.objectStore("kids");
  kidsStore.openCursor().onsuccess = function(event) {
    kidCursor = event.result;
    count = 0;
    attemptWalk();
  }
  var salesStore = transaction.objectStore("candySales");
  var kidIndex = salesStore.index("kidId");
  kidIndex.openObjectCursor().onsuccess = function(event) {
    saleCursor = event.result;
    salesLoaded = true;
    attemptWalk();
  }
  function attemptWalk() {
    if (!kidCursor || !salesLoaded)
      return;

    if (saleCursor && kidCursor.value.id == saleCursor.kidId) {
      count++;
      saleCursor.continue();
    }
    else {
      candyEaters.push({ name: kidCursor.value.name, count: count });
      kidCursor.continue();
    }
  }
}

IndexedDB は基本的にデータベースのプログラミングモデルを簡単にし、幅広いユースケースに使えます。WG はこの API を、ライブラリでラップできるようにデザインしました。例えば CouchDB のようなスタイルの API を上に重ねたりする余地は十分にあります。WebDatabase のような SQL ベースの API を IndexedDB 上に作ることも十分に可能です。仕様がまだ凍結していないこともあり、Mozilla は IndexedDB へのフィードバックを熱心に集めています。遠慮なくコメントしたり Rypple で匿名投稿してください。

高速な JavaScript とオーディオ:ブラウザ上での音声合成

David Humphrey のファンでない限り、Firefox上でオーディオ操作を実現するという彼が成し遂げた仕事のことを、あなたは知らないかもしれない。
彼は多くのデモを投稿し、Firefox 上での JavaScript の進歩を促してきた(バイナリ配列、トレーシングベースの超高速なFFT解析など)
以下は、彼の投稿の中で、私が最も気に入っているものだ。

随分前から私が気に入っているデモは、この実験を始めて以来、ずっと私が待ち続けてきたものだった。以前、私はこう書いた。自分達が成し遂げた仕事が、多くのWebのアクセシビリティに関するトラブルを解決することになるだろう。
数週間前、私は irc で、JavaScript 上でテキストをスピーチエンジンに出力するような仕組みを、誰かが作ってみるべきだと言った。そして今、私たちは完成したコードを手にしている。Yury は黙って、flite エンジンベースのそれを開発してみせたのだ。
これを実行するときには、ぜひこのことを思い出してほしい。あなたが目にしているのは、いかなるプラグインも使わず、ブラウザだけで動いている処理だということを。これは全て JavaScript だけでできているのだ。

David Humphrey による Web Audio Data API (テキストスピーチのデモ)