» Jetpack (休止)

はじめての Jetpack SDK 0.2

先日 Mozilla Labs のサイトにて Jetpack SDK の新バージョンである SDK 0.2 が公開されました。SDK 0.2 では、 SDK 0.1 で見つかった Windows 上での不具合などが修正されています。 SDK 0.2 は依然として API は充実しておらず、実用的な機能を手軽に作ることはできませんが、 SDK を用いた開発の雰囲気を一通り味わうことができます。

この記事では SDK 0.2 による開発環境のセットアップから始め、 SDK 0.2 を使用して実際に簡単な機能を開発するための手順を解説します。なお、 OS は Windows を前提としますが、おおよその手順は他の OS でも大差無いと思います。

Python インストール

Jetpack SDK を動作させるには Python のインストールが必要となります。インストール方法は OS によって異なると思いますが、 Windows の場合、 Python Japan User’s Group のサイトから Windows 用インストーラの「python-2.6.2.msi」をダウンロードし、ウィザードに従ってインストールを実施します。ここでは、インストール先を「C:\Python26\」とします。

インストール完了後、コマンドラインにて「python」コマンドを有効にするため、 Windows のユーザー環境変数の変数「Path」へ値「C:\Python26」を追加(すでに別の値が存在する場合は「;」で区切って追加)し、 Python インストール先フォルダへのパスを通します。スタートメニューの「ファイル名を指定して実行」で「cmd」と入力してコマンドプロンプトを起動し、「python -V」と入力して「Python 2.6.2」と出力されることを確認します。

C:\>python -V
Python 2.6.2

なお、 Jetpack SDK Docs には Python 2.5 以上のバージョンが必要と記載されていますが、現在のところ Python 3.0.1 には対応していないようです。また、 Windows の場合は「Windows 用拡張モジュール」が必要と記載されていますが、実際はインストールしなくても問題ないようです。

Jetpack SDK セットアップ

次に、 Jetpack SDK のセットアップを行います。 Mozilla Labs のサイトから Jetpack SDK 0.2 のパッケージをダウンロードし、お好みの位置へ展開します。ここでは、「C:\jetpack-sdk-0.2」へ展開するものとします。

Jetpack SDK を使用する際は、毎回最初に「活性化」させる必要があります。コマンドプロンプトを起動し、 Jetpack SDK パッケージ展開先フォルダへ移動し、「bin\activate」と入力します。

C:\jetpack-sdk-0.2>bin\activate
Welcome to the Jetpack SDK. Run 'cfx docs' for assistance.
(C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2>

引き続き、「cfx docs」コマンドを入力して SDK ドキュメントをブラウザで表示します。SDK ドキュメントはポート8888を待ち受けポートとしたローカルのWebサーバ上で表示されます。

(C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2>cfx docs
One moment.
Opening web browser to http://127.0.0.1:8888.

パッケージのフォルダ構成

Jetpack SDK で開発する機能の単位をパッケージと呼びます。ここからは、単純な hello-world パッケージを作成する手順へと移りますが、その前に hello-world パッケージが最終的にどのようなフォルダ構成となるかを、下表に示します。

フォルダ/ファイル 概要
フォルダjetpack-sdk-0.2 Jetpack SDK 展開先フォルダ
フォルダpackages パッケージ格納フォルダ
フォルダhello-world パッケージのルートフォルダ
ファイルpackage.json マニフェストファイル
ファイルREADME.md ドキュメントファイル
フォルダlib プログラム格納フォルダ
ファイルmain.js メインプログラム
ファイルsimple-dialog.js 自作ライブラリ

Jetpack SDK を展開したフォルダの下の「packages」フォルダ内に個々のパッケージのルートフォルダがあり、その下には「package.json」という名前のマニフェストファイルがあります。「README.md」はパッケージの詳細を記述するためのドキュメントファイルで、必要に応じて配置します。「lib」フォルダ内には、パッケージのメインプログラムや自作ライブラリのプログラムを格納します。

パッケージの作成

それでは、「C:\jetpack-sdk-0.2\packages」フォルダ下に hello-world パッケージ用の「hello-world」フォルダを作成します。次に、パッケージのルートフォルダ内にマニフェストファイル「package.json」を作成します。マニフェストファイルにはパッケージに関するメタ情報を JSON 形式で記述します。拡張機能を作成したことのある方であれば、インストールマニフェスト「install.rdf」に近いものと考えてください。ここでは、以下のような内容を記述します。

{
    "id": "helloworld@xuldev.org",
    "version": "0.1",
    "description": "This is my first package.",
    "author": "Gomita <gomita@xuldev.org>"
}

"id" プロパティはすべての拡張機能および Jetpack パッケージを一意に識別するための文字列で、一般的にはメールアドレスのような形式にします。拡張機能のインストールマニフェストの <em:id> タグに相当します。

次に、さきほどブラウザで開いた SDK ドキュメントのページを更新し、「Package Reference」に「hello-world」が追加されたことを確認してください。

プログラムの作成

引き続き、 hello-world パッケージへメインプログラムを追加して、動作できるようにします。パッケージのルートフォルダの下に「lib」フォルダを作成します。「lib」フォルダ内にメインプログラムである「main.js」ファイルを作成し、以下のような内容を記述してください。

exports.main = function(options, callbacks) {
    console.log("Hello, World!");
};

メインプログラムは「main」という名前のひとつのモジュールとなっており、 CommonJS 形式の exports.main = ... という記法によって main プロパティのみをモジュール外部からアクセス可能にします。また、 console.log は Jetpack 標準のグローバル関数のひとつで、 Jetpack SDK のコマンドプロンプトへデバッグ用文字列を出力します。

なお、現時点では console.log("こんにちは"); のように日本語を記述しても、正常に動作しません。将来的に提供されるはずのローカライズ用APIを利用することになるはずです。

テスト実行

メインプログラムを作成したら、さっそくテスト実行してみます。テスト実行するには SDK のコマンドプロンプトへ「cfx run -a firefox」コマンドを入力します。「cfx run」コマンドへ「-a firefox」オプションを付加することで、新規の Firefox プロファイルへ先ほど作成したパッケージのみがインストールされた状態で Firefox が起動します。

(C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2>cd packages\hello-world

(C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2\packages\hello-world>cfx run -a firefox
info: Hello, World!
OK
Total time: 1.531000 seconds
Program terminated unsuccessfully.

Firefox 起動後、コマンドプロンプトに「info: Hello, World!」と表示されることを確認してください。Firefox のウィンドウをすべて閉じると、テスト実行も終了します。

標準ライブラリの使用

ここからは、 Jetpack 標準ライブラリのひとつである timer ライブラリを使用して、さきほどのプログラムを少し変更してみます。 timer ライブラリはタイマー関連の処理をひとまとめにしたモジュールで、 DOM の window.setTimeout, window.clearTimeout などとほぼ同等の機能を提供します。ライブラリの詳細を調べるには、 SDK ドキュメントを参照してください。なお、 SDK ドキュメントには記載されていませんが、 timer.setInterval, timer.clearInterval も利用可能です。

メインプログラム内でライブラリをインポートして利用可能にするには、 CommonJS 形式の require 関数を使用します。メインプログラム「main.js」を下記のように修正してください。

var timer = require("timer");

exports.main = function(options, callbacks) {
    timer.setInterval(function() {
        console.log(new Date().toLocaleTimeString());
    }, 1000);
};

修正後、「cfx run -a firefox」コマンドでテスト実行し、以下のように SDK のコマンドプロンプトへ1秒おきに現在時刻が出力されることを確認してください。

(C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2\packages\hello-world>cfx run -a firefox
info: 10:37:21
info: 10:37:22
info: 10:37:23
info: 10:37:24
info: 10:37:25

自作ライブラリの作成

ここからは、 Jetpack 標準ライブラリには無い機能を、自作ライブラリとして作成する手順に移ります。拡張機能や Jetpack パッケージ内でファイル読み書きなどの高度な処理を行う場合、 XPCOM と呼ばれるコンポーネントを呼び出す必要があります。 Jetpack には、 XPCOM を使用する高度な処理はモジュール化してメインプログラムから切り離すという設計思想があります。今のところ、ライブラリだけでなくメインプログラム内でも制限なく XPCOM を利用可能ですが、もしかすると将来的にはメインプログラム内では XPCOM 使用不可となる可能性があります。したがって、 XPCOM を使用する処理は極力ライブラリとして実装した方がいいと思われます。

ここでは、 DOM の window.alert のような単純なモーダルダイアログを表示する simple-dialog ライブラリを実装してみます。 Jetpack のプログラムのコンテクストには DOM でおなじみの windowdocument といったオブジェクトが無いため、 window.alert 関数も使用できません。このようなコンテクストでダイアログを表示するためには、 nsIPromptService という XPCOM を使用します(参考)。まず、パッケージのルートフォルダ下の「lib」フォルダ内に「simple-dialog.js」ファイルを作成します。メインプログラム同様にライブラリは exports.メソッド名 = function(...) { ... }; のような CommonJS 形式で実装していきます。

ここでは、 simple-dialog ライブラリに下表の2つのメソッドを実装します。

メソッド 概要
alert(text) 引数 text のラベルとOKボタンを有する警告ダイアログを表示する。
DOM の window.alert と同等。
confirmYesNo(text) 引数 text のラベルと「はい」「いいえ」ボタンを有する確認ダイアログを表示する。
メソッドの戻り値は真偽値で、ユーザが「はい」ボタン押下時は true を返す。

「simple-dialog.js」には、以下のように記述します。

var promptSvc = Cc["@mozilla.org/embedcomp/prompt-service;1"].
                getService(Ci.nsIPromptService);

exports.alert = function(text) {
    promptSvc.alert(null, "[Jetpack]", text);
};

exports.confirmYesNo = function(text) {
    var pos = promptSvc.confirmEx(
        null, "[Jetpack]", text, promptSvc.STD_YES_NO_BUTTONS,
        null, null, null, null, {}
    );
    return pos == 0;
};

1~2行目は、 nsIPromptService を呼び出す処理です。なお、 Cc, Ci はそれぞれ Components.classes, Components.interfaces への参照であり、 Jetpack 標準のグローバル変数として定義済みです。4~6行目は simple-dialog ライブラリの alert メソッドの実装で、 nsIPromptService の alert メソッドを使って警告ダイアログを表示します。8~14行目は simple-dialog ライブラリの confirmYesNo メソッドの実装で、 nsIPromptService の confirmEx メソッドを使って「はい」「いいえ」ボタン付きの確認ダイアログを表示します。 nsIPromptService の confirmEx メソッドはユーザが押したボタンの番号(「はい」は 0、「いいえ」は 1)を返す仕様ですので、 confirmEx メソッドの戻り値が 0 なら confirmYesNo メソッドは true を返すようにします。

自作ライブラリの使用

先ほど作成した simple-dialog ライブラリをメインプログラムで呼び出し、正常に動作するかを確認します。「main.js」を下記のように修正してください。

var simpleDialog = require("simple-dialog");

exports.main = function(options, callbacks) {
    var adult = simpleDialog.confirmYesNo("Are you over 18 years old?");
    if (adult) {
        simpleDialog.alert("Welcome!");
    }
    else {
        simpleDialog.alert("Good bye!");
    }
};

「cfx run -a firefox」コマンドでテスト実行し、以下のように「はい」「いいえ」ボタン付き確認ダイアログが表示されることを確認してください。また、「はい」「いいえ」それぞれのボタン押下時に適切な警告ダイアログが表示されることを確認してください。

オフライン状態監視機能の実装

ここからは、 hello-world パッケージを修正して、もう少し実用的な機能を実装してみます。 Jetpack 標準ライブラリのひとつである observer-service ライブラリを使い、 Firefox のオンライン/オフライン状態の変化を監視する機能を実装します。

Firefox の内部ではアプリケーションに関する色々なイベントを nsIObserverService という XPCOM によってオブザーバへ通知しています。 Firefox がオフライン状態になったとき、トピック名「network:offline-status-changed」の通知が送信されます。この通知を受けて何らかの処理を実行するには、 observer-service ライブラリの add メソッドを使用します。add メソッドの第1引数には監視する通知のトピック名、第2引数には通知を受けた際に実行するコールバック関数を設定します。コールバック関数には、2つの引数が渡されますが、オフライン状態が変化した際には、第2引数に「online」または「offline」の文字列が渡されます。ここでは、この文字列の値を調べて、状況に応じた内容のダイアログを simple-dialog ライブラリを使って表示させます。

var simpleDialog = require("simple-dialog");
var observer = require("observer-service");

exports.main = function(options, callbacks) {
    observer.add("network:offline-status-changed", function(sbj, data) {
        if (data == "online") {
            simpleDialog.alert("Firefox is now online.");
        }
        else if (data == "offline") {
            simpleDialog.alert("Firefox is now offline.");
        }
    });
};

「cfx run -a firefox」コマンドでテスト実行し、 Firefox 起動後に [ファイル] → [オフライン作業] のチェックボックスをオフにし、以下のようなダイアログが表示されることを確認してください。

ドキュメントの作成

各パッケージについての詳細なドキュメントを追加することで、 SDK ドキュメントの各パッケージのリンクをクリックしたときに表示されるようになります。ドキュメントを追加するには、パッケージのルートフォルダの下に「README.md」ファイルを作成してください。「README.md」は以下のように markdown という記法にて記述します。

This is my *first* package.

* foo
* bar
* baz

「cfx docs」コマンドで SDK ドキュメントをブラウザで表示し、「hello-world」のリンクをクリックするとパッケージのメタ情報とともにドキュメントの内容が整形表示されることを確認してください。

インストーラの作成

これまで作成してきたような Jetpack のパッケージから、一般的な Firefox 拡張機能と同等の XPI インストーラ形式を作成することができます。 XPI インストーラを作成するには、 SDK のコマンドプロンプトでパッケージのルートフォルダへ移動し、「cfx xpi」コマンドを入力します。

(C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2\packages\hello-world>cfx xpi
Exporting extension to hello-world.xpi.

すると、「hello-world.xpi」というファイル名の XPI インストーラが生成されます。これを適当な Firefox のウィンドウへドラッグ&ドロップして、通常の拡張機能としてインストールされることを確認してください。

Jetpack Prototype から Jetpack Reboot へ

先日 Mozilla Labs Jetpack のサイトがリニューアルし、ようやく Jetpack Reboot の全貌が明るみに出てきたようですが、そもそも「Jetpack Reboot って何?今までの Jetpack とどう違うの?」と疑問に感じている方も多いかと思います。

端的に言うと、拡張機能として実験的に開発が進められてきた旧型の Jetpack (Jetpack Prototype) は近いうちに消滅し、新型の Jetpack (Jetpack Reboot) として新たにSDKへと生まれ変わる、ということになります。

ここでは、 Jetpack Prototype と Jetpack Reboot の違いを、コンセプト、構造、開発方法の3つの側面から解説したいと思います。

(1) コンセプト

Jetpack Prototype から Jetpack Reboot に変わっても、基本的なコンセプトは変わりません。 Jetpack Reboot のSDKによって作成したアドオンと、今現在広く流通している拡張機能とを比べた際の、前者の優位性として、おもに以下の事柄がコンセプトとして掲げられています。

  • Web開発者になじみのある HTML、JavaScript、CSS言語によって開発可能であること
  • APIライブラリを利用して迅速に開発可能であり、デバッグやメンテナンスがしやすいこと
  • 堅牢なセキュリティモデルによってユーザが安全に使用できること
  • Firefox本体を再起動することなくインストール、アンインストール可能であること

(2) 構造

Jetpack Prototype と Jetpack Reboot の構造を図示すると、このようになります。

Jetpack Prototype では、 Firefox 本体へAPIライブラリ+動作環境である Jetpack “拡張機能” をインストールし、その上で JavaScript で書かれた個々の小さな機能 (Jetpack Feature) を動作させる、という構造になっています。将来的には Jetpack 拡張機能の部分を Firefox 本体側に取り込む(ピンク色の点線で囲った部分全体が Firefox 本体となる)という構想もあったようです。しかし、まだ発展途上にある APIライブラリが Firefox 本体に取り込まれてしまうと、APIライブラリの迅速な開発が妨げられてしまう問題が生じます。また、すべての Jetpack Feature がAPIライブラリを共有することになりますので、各 Jetpack Feature が異なるバージョンのAPIを使用している場合に互換性の問題が生じます。

一方、Jetpack Reboot では、 Firefox 本体は Jetpack 用のAPIライブラリを持たず、個々のアドオン機能がAPIやブートローダを包含したひとつのパッケージとなっています。これにより、 APIライブラリは Firefox 本体とは独立して迅速な開発を進めることができ、個々のアドオン機能のパッケージが異なるバージョンのAPIを包含しても互いに干渉することはありません。また、このパッケージは既存の拡張機能(XULベースのアドオン)と同じXPIインストーラとして配布可能ですので、既存の拡張機能と同じようにインストール・アンインストールが可能です。さらに、将来的には Firefox 本体側の拡張機能管理システムが改良され、 Jetpack のブートローダを包含したパッケージは、 Firefox を再起動することなくインストール・アンインストール可能となる予定です。

(3) 開発方法

Jetpack Prototype から Jetpack Reboot へと変わることで、アドオン機能の開発方法は大きく変わります。
Jetpack Prototype では JavaScript のプログラムを一個記述するだけで、簡単に Feature の開発ができました。一方、 Jetpack Reboot では Jetpack SDK と呼ばれる開発環境を用い、 JavaScript のプログラムやJSON形式のマニフェストファイルなどを適切に配置してパッケージングを行う必要があります。今現在公開されている Jetpack SDK 0.1 は Python 言語で記述されたコマンドラインのツールとなっており、 Jetpack Prototype と比べると敷居が高くなったと思います。しかし、将来的には FlightDeck と呼ばれるブラウザ上で動作するGUIの開発環境により、お手軽な開発が可能となる予定です。

現時点の最新版である SDK 0.1 ではまだ使用可能なAPIが少なく、Jetpack Prototype の Feature のように色々な機能は開発できませんが、近日中に SDK 0.1 を使って Windows 7 上でパッケージングを行う手順についても解説したいと思います。

Jetpack Ambassadors Program の簡単なレポート

2月8日~9日の2日間、カリフォルニアにある Mozilla 本部で開催された Jetpack Ambassadors Program に参加してきました。このイベントの趣旨は、 アドオン開発コミュニティのメンバーが Jetpack の技術と啓蒙について学ぶというもので、日本からは Gomita とあかつかさんの2人が参加しました。

まずは、写真を交えつつ、簡単なレポートを行いたいと思います。



1日目の朝は、まず Mozilla オフィスのラウンジで朝食を食べながら自己紹介をしました。 Jetpack Ambassadors Program の参加者は10人ほどで、日本、台湾、アメリカ、カナダ、チリ、アルゼンチン、ドイツ、デンマークなど、世界各地のアドオン開発者、コミュニティメンバーなどがいました。

その後 “Road to Jetpack 1.0″ と題して、 Jetpack 1.0 に向けたプランに関するプレゼンが行われました。 FlightDeck と呼ばれる管理用 GUI の紹介がありました。

そして、 Mozilla で働いている人たちがたくさん集まってきて、活気のあるライトニングトークが行われました。

会議室へ移動していくつかの説明を受けた後、プレゼンテーションの研修がありました。より多くの方々に伝えることを重要視していることが窺い知れました。

休憩時間の一こまです。

こんな感じの枠組みを使って、 Jetpack に関するプレゼンの構成を組み立てていきます。

Daniel さん、 mitcho さんを中心に、 Jetpack のプレゼン構成について熱い議論が交わされました。

プレゼン研修の後は、いよいよ本イベントの核心となる Jetpack Reboot についての説明が始まりました。

aza さんによる Jetpack Reboot のコンセプト紹介です。

新しいAPI (Toolbar と Bookmarks)の紹介もありました。

ソースコードを参照しつつ、 Jetpack Reboot の実装の解説です。

Jetpack Reboot SDK を使って、実際にアドオンを開発するデモンストレーションも行われました。

最後は、皆でロックバンドゲームやビリヤードをやり、親睦を深めました。





以上、簡単なレポートでした。2日間のイベントを終えた感想としては、 Mozilla が Jetpack (Reboot) に大きな力を注いでいることを強く印象付けられました。また、 Jetpack Reboot はコンセプトの面および技術的な面において現行の Jetpack から大きな進化を遂げており、興味深いものでした。

Jetpack Reboot のコンセプトや、実際に SDK を使用した開発手順などの詳しい情報についても、なるべく早く modest へアップしていきたいと思います。

Mozilla 勉強会@大阪でJetpack について発表しました

こんにちは、mollifier です。

2月20日に行われた Mozilla 勉強会@大阪でJetpack について発表しました。

今回は Jetpack Feature を書いたことがない人向けに、開発の導入から始まり、よく使う機能の実装方法、はまりやすいポイントについてお話ししました。

細かい説明をたくさん詰め込みすぎたところもありますが、その分開発する上での資料として活用できると思います。発表資料は slideshare に載せたので参考にしてください。

Jetpack は大きな機能の実装ももちろんできますが、ちょっとした工夫を小さなスクリプトで実現することもできるので、みなさんもぜひ Jetpack Feature の作成に挑戦してみてください。

Jetpack0.7がリリースされました

はじめまして、こんにちは!con_mame(こんまめ)です。

先日は、Mozilla勉強会でJetpackについて話させて頂きました(時間超過すいません><) 使用したスライドは、http://d.hatena.ne.jp/con_mame/20091220#1261301099 にのっけています。

さて、先日Jetpack0.7がリリース(http://mozillalabs.com/jetpack/2009/12/23/announcing-jetpack-0-7/)されました。今回のリリースではAPIの追加と既存の不具合の修正が行われています。

今回のリリースでFirst run APIが追加されました。このAPIを使用することでFeatureのインストール後にFeature作者が指定したサイトやメッセージを表示することが可能になります。主な利用方法としては、Featureの使用方法を記載したページを表示させるなどがあげられます。記述方法も非常に簡単で、manifest内にfirstRunPageプロパティを記述するだけです。以下の様に記述する事で、Featureのインストールが完了した際に表示されるページの内容の一部が指定した内容に書き換えられます。アドレスだけを指定した場合はiframe内に指定したサイトが表示されます。

//書き方1(メッセージを表示/E4Xでも記述出来ます)
var manifest = {
   firstRunPage: '

インストールありがとう! 使い方

' }; //書き方2(サイトを挿入) var manifest = { firstRunPage: "http://hoge.com/howtouse.html" };

簡単ですね。

この他には、MeというAPIも追加されています。こちらはCallback関数を指定することでインストール完了後に処理を実行することが出来ますが、個人的にはあまり利用方法が思いつきません。

jetpack.future.import("me");
jetpack.me.onFirstRun(function () {
   jetpack.notifications.show("Oh boy, I'm installed!");
});

この様に記述出来ます。詳しくはhttps://developer.mozilla.org/en/Jetpack/Meta/Me を参照して下さい。

今回のリリースではSettings APIとStatusBarの挙動が修正されています。
Settings APIでは、about:jetpack→Installed Features内の、SettingsボタンがSettings APIを使用していないFeatureについてはクリックが出来ないようになりました。(Ver.0.6ではクリックすることが可能で、クリックするとエラーが表示されていました)

StatusBarの修正は、StatusBarにFeatureを追加するとStatusBarの高さがどんどん高くなっていき、Featureのアイコンや文字が階段状に配置されてしまうという問題が修正されています。
しかし、修正されたコードを見ると、StatusBarのHeightを16pxに固定するように記述されているので、StatusBarに表示する文字のサイズを大きくしたりすると、文字の下部が見切れてしまいますので注意が必要です。(標準の文字サイズであれば問題ありません)

今回のリリースでは以上の点が目立った追加・変更かなと思います。

Mozilla 勉強会での Jetpack 会議

あかつか です。こんにちは。

先日行われた Mozilla 勉強会 では 3分Jetpacking の発表の後に、Jetpack へのご意見や要望、問題点などについて議論の場を設けて頂きました。おかげさまで、とても濃い話しができたと思いますし、さまざまなご意見を聞くことができました。議論の内容はご意見や要望などなどのページにまとめておきました。どうもありがとうございました!!

あ、あと、いちおう、この間発表した 3分Jetpacking も公開しました。

ではでは。

戻りやすくする:jetback

長いドキュメントを読み終わったあと、マウスカーソルはどこにあるだろうか。スクロールバーを多用する人にとってはスクロールバーの近くに、マウスホイールでスクロールをする人にとってはドキュメントのどこかにマウスカーソルはありそうである。ところで、”戻る”ボタンはブラウザのどこにあるだろうか。およそブラウザの左上に頑なに鎮座していると思われる。遠い。ならば、もっとカーソルの近いところにこの機能を持ってきてはどうだろうか。
てっとりばやく、ドキュメントの一番下にこの機能を追加してみる。

実装の目次

  • ドキュメント読み込み完了のイベントを取る。
  • history があるか検査する。
  • ボタンを追加する。
  • 右側へ。
  • 色気を出す。

ドキュメント読み込み完了のイベントを取る。

ここはいつもと同じです。(説明はこちらをご参照くださいませ)

jetpack.tabs.onReady(function(targetDocument) {
  if (targetDocument.defaultView.frameElement) {
    return;
  }
});

history があるか検査する。

“戻る”ボタンですので、閲覧履歴がないと意味がありません。そこで閲覧履歴の有無を検査します。具体的には window.history を検査しますが、window と書くだけでは Jetpack の名前空間内の window になってしまいます。読み込んだドキュメントの window を見るためには引数 targetDocument の defaultView にアクセスする必要があります。

jetpack.tabs.onReady(function(targetDocument) {
  var contentWindow = targetDocument.defaultView;
  if (contentWindow.frameElement) {
    return;
  }
  //履歴があるかどうか検査する
  if (! contentWindow.history.previous) {
    return;//無いようだ。
  } 
});

ボタンを追加する。

ボタンとなる div 要素をドキュメントの一番最後に追加します。また、クリックイベントを取得して、一つ前のページへ戻します。

jetpack.tabs.onReady(function(targetDocument) {
  var contentWindow = targetDocument.defaultView;
  if (contentWindow.frameElement) {
    return;
  }
  //履歴があるかどうか検査する
  if (! contentWindow.history.previous) {
    return;//無いようだ。
  }
  //ボタン要素
  var back = targetDocument.createElement("div");
  back.textContent = "戻る";
  //戻る機能を付ける。jQueryオブジェクトにしています
  var jback = jQuery(back);
  jback.click(function() {
    contentWindow.history.back();
  });
  //ドキュメントに追加
  targetDocument.body.appendChild(back);
});

右側へ。

左側にボタンがあると、スクロールバーから遠いので、右側にもってくる。

jetpack.tabs.onReady(function(targetDocument) {
  var contentWindow = targetDocument.defaultView;
  if (contentWindow.frameElement) {
    return;
  }
  //履歴があるかどうか検査する
  if (! contentWindow.history.previous) {
    return;//無いようだ。
  }
  //ボタンの下のdivを用意して、右側に寄せる。
  var backdiv = targetDocument.createElement("div");

  //ボタン要素
  var back = targetDocument.createElement("div");
  back.textContent = "戻る";
  //右側に配置。あとで微調整ができるように absolute にしてある
  back.setAttribute("style", "position:absolute; right: 10px;");
  //div にボタンを追加
  backdiv.appendChild(back);

  //戻る機能を付ける。jQueryオブジェクトにしています
  var jback = jQuery(back);
  jback.click(function() {
    contentWindow.history.back();
  });
  //ドキュメントに追加
  targetDocument.body.appendChild(backdiv);
});

色気を出す。

あまりにもさっぱりしているのでイメージを利用してちゃんとボタンっぽくしてみます。現状(ver 0.6)の Jetpack では外部ファイルを同一パッケージにすることができません。イメージも同様です。そこで、イメージを Base64 でエンコードして javascript ファイルに組み込みます。
利用イメージ:
back

jetpack.tabs.onReady(function(targetDocument) {
  var contentWindow = targetDocument.defaultView;
  if (contentWindow.frameElement) {
    return;
  }
  //履歴があるかどうか検査する
  if (! contentWindow.history.previous) {
    return;//無いようだ。
  }
  //ボタンの下のdivを用意して、右側に寄せる。
  var backdiv = targetDocument.createElement("div");
  //ボタン要素
  var back = targetDocument.createElement("div");
  //イメージを付ける
  //右側に配置。あとで微調整ができるように absolute にしてある
  back.setAttribute("style", "background: url('data:image/png;base64,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'); width: 128px; height: 128px; position:absolute; right: 10px;");  //div にボタンを追加
  backdiv.appendChild(back);

  //戻る機能を付ける。jQueryオブジェクトにしています
  var jback = jQuery(back);
  jback.click(function() {
    contentWindow.history.back();
  });
  //ボタンを押したときのイメージへ
  jback.mousedown(function() {
    jback.css({"background-position":"right"});
  });
  //もとのイメージへ
  jback.mouseup(function() {
    jback.css({"background-position":"left"});
  });
  //ドキュメントに追加
  targetDocument.body.appendChild(backdiv);
});

これで完成です。ドキュメントを読み終えると戻るボタンが目に入るようになり、サイズもかなり大きくしてあるのでかなり戻りやすくなっていると思います。ただし、このボタンは常にこれを押さなければならないというものではなく、マウスの位置に応じ、ブラウザの戻るボタンを使うなど、選択しながら利用すればよいのかと思います。

最後に

このソースコードおよび install html を固めてこちらにおきます。このコードではさらに、履歴の一番始めまで戻る機能もあわせて実装してみました。

Mozilla勉強会で発表してきました

変態Vimperator使いのteramakoです。こんにちは

Mozilla 勉強会 « Mozilla Developer Street (modest)にて発表してきました。

内容としては

かなり異色の部類になるかと思われる開発者向けのfeatureの紹介となってます。

jetpack feature installerに関してはローカルのJetpack FeatureファイルをインストールするFeature – hogehogeで紹介していたこともあり、id:con_mameさんに先に紹介されたり、懇親会で「使っていますよ」と言ってくれる人がいたりと嬉しい誤算がありつつ、なかなか楽しい勉強会でした。

Jetpackに関しては皆いろいろ思うところがあるようで、それなりに議論できたのかなと思います。

私自身それなり思うところがあるわけですが、Jetpackは今後、GoogleChromeのChromeExtensionと比較され続けるかと思います。ChromeExtensinと比較して優位性を示せるかが課題ではないでしょうか。本心としてはTwitter / teramakoで書いた通りなのですが・・・。

開発者を募集しているようです

話はちょっとそれますが、JetpackのMLでWe’re looking for a Jetpack API Developer! – mozilla-labs-jetpack | Google グループなんてのが流れてます。ちょっと条件が厳しいですが・・・、自信のある方は応募してみると現状を打開できるかも!? です。

さらに余談

そうそう、懇親会で私がLightweight Language Television (LLTV)にて発表したものが話題(XULとcanvasを使って画面いっぱいにSLを走らせるというもの)にあがり、デモったのですが、その時の資料はSL command – LLTV にあります。資料はHTML+JavaScriptで出来ていますので、該当ソースを抜きとれば貴方のページでSLを走らせることができますよ :) デモで使ったコードのソースは/lang/javascript/vimperator-plugins/trunk/sl.js – CodeRepos::Share – Tracです(注:Vimperatorのプラグインとして動作するように作られているので通常では動きません)。

意見や要望などなど

2009/12/19 に行われた第1回 Mozilla 勉強会において、 Jetpack に対する意見や要望、問題点などについて活発な議論がなされました。議事録をカテゴリごとに少しまとめた形でここに報告いたします。さらなるご提案やご意見などがございましたら、コメント欄、あるいはこのページを直接編集して書き加えてくださいませ。尚、ここで得られたご意見をもとにして、来年早々 Jetpack 開発チームへフィードバックしに行きます!!

Jetpack開発に対して

バグ

  • Bespin :日本語が入力できない
  • Firebug が 1.4 以上だとうまく動かない
    • うまくエラー補足ができない
  • Menu の上書きで、挙動がおかしくなるときがある
  • Settings の Manifest は、storage.settings を import する前に書かなければならない
    • 感覚的には import が頭にありそうだし
  • Jetpack Gallery :ソースコードのサニタイズがあやしい
  • Jetpack のアップデートアルゴリズムがへぼすぎる
    • 現状はコードを全て比較しているだけ
    • >> MD5ハッシュの比較でいいんじゃね?

セキュリティ

  • Jetpack Gallery:警告画面がなくなってしまった
  • 自動更新の怖さ
    • Jetpack Gallery にも言えること

この API は絶対欲しい!

  • パスワード系入力
    • パスワードマネージャとの連携
    • 以下のようにパスワードマネージャから情報を引っ張ってこれるAPI
      let pass = jetpack.password.get("example.com")
      // pass[0].user == "my name"
      // pass[0].password == "password"
    • 逆に、パスワードマネージャにパスワードを追加するAPIが必要か?
    • パスワードを削除するAPIは?
  • ツリースタイルタブを実現するためのAPIが欲しい
  • 拡張と Jetpack Feature 、および Feature 同士の連携
    • 双方でメッセージを送り会える仕組みが欲しい
      • アイディア1:nsIObserverServiceをモデルにしたAPI
        <受け取り側>
         jetpack.message.listen(
         'onTreeItemCreated',
         function(aData) {
         return <><button>X</button></>;
         }
         );
         <送出側>
         let myItem = '';
         let responses = jetpack.message.send('onItemCreated', 'foo');
         for each (r in responses) {
         myItem += r;
         }
         実装するときは、nsIObserverServeiceを使うといいんじゃないか?
         (Mozilla内部のメッセージは拾わない・拾えないように制限する必要あり)
      • アイディア2:DOMEventをモデルにしたAPI
  • about:xxx を自由に追加するAPI
  • 独自のプロトコルハンドラを定義するAPI
  • アドブロックのような、Firefox自身が行っている通信の内容に割り込む・フックを掛けるAPI
  • 今XPCOMを使わないと出来ない・特権が必要な機能に対応するAPIは一通り欲しい?
    • 少なくともFrozenになっているインタフェースに対応するAPIは優先して取り込んでもらいたい
  • Google Chrome用のAPIと互換性のあるAPI
    Google Chrome用拡張機能をそのまま移植できるようにする>>開発者の流出を防げる?
  • サブメニューをもう少し簡単に作りたい
  • pageModsの適用対象について、例外を指定したい
  • 外部スクリプトを簡単に読み込むAPI
    Components.utils.import()やmozIJSSubScriptLoaderみたいな
  • setting API で設定できる少ない

APIポリシー

  • HTML5 で出来ることは HTML5 でやる。独自のAPIは作らない。
  • XPConnectは使えないようにした方がいいんじゃないのか?
    使えるようにしてしまうと
    =>それを使ったFeatureが出てくる
    =>普及する
    =>ユーザがそれに依存した生活を送るようになる
    =>今更XPConnectを禁止できなくなる
    というシナリオが考えられるので、今のうちに禁止した方がいいのでは?
  • rawも使えないようにした方がいいんじゃないの?
    使えるようにしてしまうと
    =>それを使ったFeatureが出てくる
    =>普及する
    =>ユーザがそれに依存した生活を送るようになる
    =>今更rawを禁止できなくなる
    というシナリオが考えられるので、今のうちに禁止した方がいいのでは?
  • API、ライブラリのバージョンについて
    バージョン指定してAPIやライブラリを読み込む機能 like gem of Ruby
    後方互換性を損なう変更をAPIに加えたくなる時はいつか絶対に来るので今から備えておいた方がよい
  • Firefox本体のUIの文法、作法から外れるような事も実現できるようにしていいのでは?
    例:Backボタンの挙動を乗っ取るAPIなど。
    Operaの「巻き戻し(Rewind)」を実現しようと思ったら、Backボタンの挙動を完全に乗っ取らないといけない。
    そういうこともできるように自由度を高く。
    APIとのバランスか。
  • fuel の二の舞にはならないように
    • 中途半端な機能しかなかった
    • メモリリークがひどかった
  • イノベーションにAPIは必要なのか?
    Greasemonkeyは貧弱なAPIしかないのにあれだけイノベーションが起こった
    Jetpackもそのくらいでいいのかもしれない

ドキュメント

  • 解説記事が少ない
  • アドオン開発者がJetpackをさわるまでのパスを作る。
    アドオンではこうやってたところがJetpackではこうなります。
    =>むしろ、全然別物として作り始めた方がわかりやすいという現実はある。
  • ドキュメント場所に一貫性が無いっつー話
    フリーズしたAPIからどんどんMDCに移動して!

Jetpack拡張について

  • 内蔵エディタによる開発はめんどくさい
    • いちいちタブを切り替える必要がある
    • 外部エディタが使えれば問題がない
  • エディタおよびインストーラ含め開発効率が悪い
    ※具体的な案が欲しいっすね

Jetpackギャラリーについて

  • 一度「削除」すると、同じ名前ではFeatureを登録できない
    =>セキュリティ的には、できなくていいんじゃないか
    Twitterで、すでに退会したユーザと同じ名前でアカウントを取り直して乗っ取るということができてしまう。
  • AMOでできることはできるように
    • レビューシステムによる安全性の担保
    • 対応バージョン判別(APIバージョン?)
    • セキュアな自動アップデート

Jetpack Featureのパッケージング、インストールおよびアップデートについて

  • インストール・アップデートにおけるセキュリティ関連
    現状では、新しかったら問答無用でインストールされてしまう。
    悪意のある開発者が、無害なFeatureを登録した後アップデートでマルウェアを登録したら、ユーザの環境にそれが勝手に貼ってしまう!
  • セキュリティのモデル
  • マニフェスト
    • バージョンアップの仕組み
    • 外部スクリプトとの連携
  • パッケージ化
    画像、HTMLなどをパッケージングして提供できるように。
    一つのJSファイルの中に全部置かなきゃ行けないのはつらい。

みらい

  • Jetpack の位置づけがあいまいだ
    メインになるかならないか。はっきりして欲しい。開発者が本気で取り組めない。
  • グリースモンキーとの共存は? 完全に置き換えるの?
    • むしろ、GMスクリプトを全く修正なしに動かせるようにしていいのでは?
    • そういう意味では Google Chrome 拡張も?
  • ユーザがプログラムを書ける時代がやってくるか?
    • エディタを賢く
      • コード補完
      • リファレンス
      • ローカライズ
      • 国際化
    • ビジュアルプログラミングは?
  • 外部アプリケーションとの連携(iTunes)って本当に必要か?
    • 必要だとしたらどんなAPIが必要か?
    • OS化してきているブラウザにとっては、アプリ連携は必須なのかもしれない?
  • アドオンでJetpackのAPIを追加できるようにしてほしい
  • プロポーサルの方法
    プロポーサルを出す文化が日本には無い

    • バグトラックみたいなシステムがあればやりやすい
    • 日本でそういうチームを作る!

UI

参考URL: https://developer.mozilla.org/en/Jetpack/UI

Menu

参考URL: https://developer.mozilla.org/en/Jetpack/UI/Menu
参考URL: https://wiki.mozilla.org/Labs/Jetpack/JEP/14

ツールメニューやコンテキストメニューなどのメニュー群を扱います。

ピクチャ 6



※メニューAPIは全て確定ではないので、以下のようにインポートしてから利用します。

jetpack.future.import("menu");

コード例:

jetpack.future.import("menu");
jetpack.menu.context.page.on("a").add(function (context) ({
  label: "Jetpacker!",
  command: function () console.log("押したのは::"+context.node.href)
}));

Constructors

空のメニューを作る : jetpack.Menu()

var menu = new jetpack.Menu();

アイテム付きでメニューを作る : jetpack.Menu(menuitems)

var menu = new jetpack.Menu(["メニュー1", "メニュー2", "メニュー3"]);

プロパティ付きでメニューを作る : jetpack.Menu(properties)

var menu = new jetpack.Menu({
        label: "sample menus",
        beforeShow: function (menu) {
          console.info("表示の前に呼ばれますわ。");  
        }  
}) ;

上記メニューを「ツール」メニューに装着

ピクチャ 2

var menu = new jetpack.Menu({
        label: "sample menus",
        beforeShow: function (menu) {
          console.info("表示の前に呼ばれますわ。");  
        }  
}) ;
jetpack.menu.tools.add(menu);

Properties

メニュー表示前に呼ばれます : beforeShow

以下は、メニューのラベルを現在時刻にするサンプルです。

var menu = new jetpack.Menu({
        beforeShow: function (menu) {
            menu.set(new Date().toString());
        }  
}) ;

メニューが非表示になる前に呼ばれます : beforeHide

var menu = new jetpack.Menu({
        beforeHide: function (menu) {
            console.info("メニューが消される前に呼ばれるっす。");
        }  
}) ;

メニューの表示状態です : isShowing

if (menu.isShowing == true) {
    //表示中
} else {
    //非表示中
}

メニューの持つアイテム配列 : items

console.info("メニューが持つアイテム数は:"+menu.items.length);

Methods

メニューの末尾にアイテムを追加します : add(items)

例では「ファイル」メニューに追加しています。

ピクチャ 3

var items = ["追加1", "追加2"];
jetpack.menu.file.add(items);

メニューから全てのアイテムを削除します : clear()

menu.clear();

:contextOn(node)

メニューを非表示にします:hide()

menu.hide();

メニューアイテムを引数のtargetの上に追加します:insertBefore(newItems, target)

ピクチャ 4

//「オフライン作業」の上に item1 を追加
var items1 = ["item1"];
jetpack.menu.file.insertBefore(items1, "オフライン作業");

//正規表現で id や xulid を指定できるとあるんだけど、うまくいかないなぁ。
//var items2 = ["item2"];
//jetpack.menu.file.insertBefore(items2, /menu_newNavigator/);

//指定したインデックスにアイテムを挿入
//0 は一番上
var items3 = ["item3"];
jetpack.menu.file.insertBefore(items3, 0);
//マイナスは一番下のメニューからの順番(一番下に入れる場合は add を使う)
var items4 = ["item4"];
jetpack.menu.file.insertBefore(items4, -1);

target で指定されたアイテムを返します:item(target)

//0番目のアイテム、つまり一番上のアイテムを取る
var item = jetpack.menu.file.item(0);

:popupOn(node)

target で指定したアイテムをメニューから取り外します:remove(target)

//一番上のアイテムを取り外す
jetpack.menu.file.remove(0);

target で指定したアイテムと newItems を入れ替えます:replace(target, newItems)

サンプルでは オフライン作業 と item1 item2 を入れ替えます。

ピクチャ 5

var items = ["item1", "item2"];
jetpack.menu.file.replace("オフライン作業", items);

メニューをリセットします:reset()

//Jetpack で操作する前の状態に戻ります
jetpack.menu.file.reset();

//Jetpack で作った menu に対しては clear() と同じ意味を持ちます。

メニューのアイテムを items に差し替える:set(items)

var items = ["item1", "item2"];
menu.set(items);

メニューを即座に表示します:show(anchorNode)

//anchorNode は DOM NODE あるいは NODE をくるんだ jQuery オブジェクトが入ります。
menu.show(anchorNode);

Menuitems

メニューに追加できるアイテムの属性例です。

ピクチャ 6

var item = {
  command: function() {
    //このメニューアイテムが選ばれたときに、この function が呼ばれます。
    console.info("ここ");
  }, 
  disabled: true, //false であれば有効になります。
  icon: "/wp-content/themes/modest/images/footer-logo.png", //メニューアイコン
  label: "アイテムのラベル",
  mnemonic: "A", //ショートカットキー
  xulId: "sample_menu_item1" //xulid を指定できます
}

var separator = {
    type: "separator" // ここに入れられるのは "separator" のみ。これが指定されるとセパレータになる。
}

var item2 = {
  disabled: false,
  icon: "/wp-content/themes/modest/images/footer-logo.png", //メニューアイコン
  label: "アイテムのラベル2"
}

jetpack.menu.file.add(item);
jetpack.menu.file.add(separator);
jetpack.menu.file.add(item2);

Menu bar menus

定義されている menu 群

jetpack.menu.file

ピクチャ 7

var items = ["Jetpacker!"];
jetpack.menu.file.add(items);

jetpack.menu.edit

ピクチャ 8

var items = ["Jetpacker!"];
jetpack.menu.edit.add(items);

jetpack.menu.view

ピクチャ 9

var items = ["Jetpacker!"];
jetpack.menu.view.add(items);

jetpack.menu.history

ピクチャ 10

var items = ["Jetpacker!"];
jetpack.menu.history.add(items);

jetpack.menu.bookmarks

ピクチャ 11

var items = ["Jetpacker!"];
jetpack.menu.bookmarks.add(items);

jetpack.menu.tools

ピクチャ 12

var items = ["Jetpacker!"];
jetpack.menu.tools.add(items);