Safari Extension 三分クッキング!

Safari Extension 作りたい! という方にお届けする、三分クッキング!

HTML5 + JavaScript を使って簡単な機能拡張(extension)を作ってみます。

本日のメニュー

ツールバーで動く時計

完成予定図:

最大の難関

Safari Extension を作るにあたって、最大の難関は Apple ID の登録と、Safari Developer Program への登録です。

三分クッキングとしては、「既に登録されたアカウントがこちらになります」と別のお鍋を取り出す場面です。

軽く要所要所だけ説明しますので、フィーリングとリーディングとやる気で乗り切ってください。

  1. Safari Developer Program のページを開いて「Join now」を押します。
  2. 次のページでは登録状況によってチェック先が変わります。
    • Apple ID を持っていない人:左上の「I need to create a 〜」にチェック
    • Apple ID を持っているけど Apple Developer Program に登録していない人:左下の「I currently have an Apple ID〜」にチェック
    • Apple Developer Program に登録したけど課金してない人:右上の「I'm registered as a developer〜」にチェック
    • ADC Select、Premier、Student Member のいずれかで登録している人:右中の「I'm currently an ADC Select, Premier〜」にチェック
    • iPhone Developer Program か Mac Developer Program で登録している人:右下の「I'm currently enrolled in iPhone Developer〜」にチェック

ここから先は、気合いと根気と負けん気で乗り切ります。

住所や名前を入力する場合は、日本語ではなく半角英数で入力してください。さもないとバグに巻き込まれて涙目になります。

最終的に Safari Developer Program の登録まで完了すると、以下のような画面が出てきます。本当にお疲れ様でした。


証明書のダウンロード&インポート

自作の Safari Extension を作るには、Apple から開発者としての証明書をもらって署名する必要があります。面倒ですが、これをやらないと動かせないという大切なステップですよ!

Apple から「証明書」をもらうには、「証明書要求書」というややこしいものが必要です。Mac なら簡単に作れます。Mac ならね。(他のOSはググってくださいごめん><)

Mac で「アプリケーション→ユーティリティ→キーチェーンアクセス」と選んでいき、キーチェーンアクセスを起動します。

メニューバーから「キーチェーンアクセス→証明書アシスタント→認証局に証明書を要求」を選ぶと、証明書アシスタントが起動します。

  • 「ユーザのメールアドレス」に自分のメールアドレス
  • 「通称」に自分の名前
  • 「要求の処理」を「ディスクに保存」にチェック

「続ける」を押すと、証明書要求書の保存先を聞かれるので、適当なフォルダに保存します。

次に Safari Extension Certificate Utility ページを開きます。

初回アクセス時は「Request Certificate」の画面が開くので、右下の「Launch Assistant」→「Continue」とクリックします。

「Select the Certificate Signing request (CSR) file〜」という画面が出てきたら、先ほど作った証明書要求書を選択して「Generate」を押します。

くるくる回るアニメーションを見ながら待ちます。終わったら、「Continue」を押して、作られた証明書を「Download」します。

最後にダウンロードした証明書を開くと、証明書追加の確認が出るので「追加」を押せば準備完了です。

いよいよ本題

以下、テンプレ。

  1. まずは Safari 5 をダウンロード&インストールします。
  2. Safari 5 を起動してメニューから環境設定を開きます。(Mac だと Cmd+,)
  3. 詳細タブを開いて、「メニューバーに''開発''メニューを表示」にチェックを入れます。
  4. メニューバーに「開発」が追加されるので、その中の「機能拡張を有効にする」にチェックを入れます。
  5. 以上で、機能拡張が有効になり、Safari Extension をインストールできるようになります。

ここから本題。

  1. メニューバーの「開発」から「機能拡張ビルダーを表示」を選ぶと、真っ白くて潔い画面が現れます。
  2. 左下の「+」ボタンを押して「新規機能拡張」を選びます。
  3. 保存先を聞かれるので、適当なフォルダに「Clock」という名前で保存します。(「Clock.safariextension」という名前のフォルダが作られます)

ここまでで、こんな感じになっていると思います。

Safari Developer」の部分が「Safari デベロッパ証明書がありません」となっている場合は、証明書のインストールが出来ていないです。

HTMLファイルの作成

今まさに作られた「Clock.safariextension」フォルダの中に「bar.html」という名前でファイルを作ります。

Clock.safariextension
|-- Info.plist
`-- bar.html

ファイル構成はこんな感じになると思います。

「bar.html」の中身は、以下のようにします。HTML4と言っても通じるシンプルなHTML5で書きました。

<!DOCTYPE html>
<html>
<head>
    <title>Clock</title>
</head>
<body>
    <span id="hours"></span>
    :
    <span id="minutes"></span>
    :
    <span id="seconds"></span>

    <script type="text/javascript">

    function updateClock() {
        // 現在時刻を取得
        var now = new Date();
        var hours = now.getHours();
        var minutes = now.getMinutes();
        var seconds = now.getSeconds();

        // 1桁だったら頭に0を付ける
        if (hours < 10) hours = "0" + hours;
        if (minutes < 10) minutes = "0" + minutes;
        if (seconds < 10) seconds = "0" + seconds;

        // ページに反映する
        document.getElementById("hours").innerHTML = hours;
        document.getElementById("minutes").innerHTML = minutes;
        document.getElementById("seconds").innerHTML = seconds;
    }

    // 0.5 秒に 1 回 updateClock 関数が呼び出されるようにする
    setInterval(updateClock, 500);

    </script>
</body>
</html>

これで、もうファイルを作ったり、コードを書いたりする必要はありません。やったね!

Clock の設定

機能拡張ビルダーで作成した Clock の設定を以下のように行ってください。

  • 機能拡張の情報
    • 表示名: 「俺様時計」とか「うにくろっく」とかどうぞご自由に
    • 作成者: あなたのなまえをいれてください
    • 説明: 「時を計ります」とか適当に入れておけばOK
  • 機能拡張の詳細
    • バンドル識別子: もし example.com というドメインを持ってるなら com.example.clock のように逆にして clock をくっつけます。無いなら適当で。
  • 機能拡張クローム
    • バー: 「新規バー」を押して、以下のように設定してください。

以上で、完成です!!

動かしてみる

早速、機能拡張ビルダーの右上にある「インストール」を押してみましょう!

ツールバーがニュッと出てきて、時計が動き出せば完璧です。

やったね!

Safari Extension で出来る事一覧

他にも Safari Extension はいろいろな事ができます。

  • 独自ツールバーの追加
  • ツールバーに独自ボタンの追加
  • コンテクストメニューに項目の追加
  • 独自タブ・ウィンドウの追加
  • ウェブページにスクリプトの注入(グリモンっぽいの)
  • ウェブページにスタイルシートの注入
  • バックグラウンドで動き続けるグローバルページ
  • グローバルページ、ツールバー、ウェブページ間でのメッセージング
  • 読み込みブロックが可能な beforeload イベント
  • 永続的に記憶される設定領域
  • 自動更新機能

まとめ

3分なんて無理でした><

niconicofavlist.user.js ver 1.20

ニコニコ動画でマイリストの新着を知る Greasemonkey スクリプト をバージョンアップしました。

インストール: niconicofavlist.user.js (使い方

コメントで要望があった、マイリスト自体の並べ替えを実装しました。

変更点

  • 追加: 設定画面で、マイリストを並べ替えられるようになりました。
  • 修正: Safari で、設定が保存した際に自動的にタブが切り替わらない不具合を修正しました。

マイリストの並べ替えについて

ver 1.19 での仕様変更はマイリストの内容(=動画)の並び順に関するものでしたが、コメント欄で「登録したマイリスト自体を並べ替えたい」という要望が多くあるようでしたので、機能追加してみました。

設定画面で、マイリスト名の右に「▲」「▼」「↑」という3つのボタンが追加されています。それぞれ「1つ上へ」「1つ下へ」「先頭へ」という意味です。

Enjoy!

niconicoplaylist.user.js ver 1.13

ニコニコ動画でプレイリストが使える Greasemonkey スクリプト をバージョンアップしました。

インストール: niconicoplaylist.user.js (使い方

長らく放置していましてすみません!

変更点

  • プレイヤーが最大化している時は、プレイリストが隠れるようにしました。
  • Safari 4 + GreaseKit に対応しました。
  • ニコニコ動画のHTML変更に対応しました。
    • 「ページ中の動画を追加」でリンクが追加されないのを修正しました。
    • フォントサイズが大きくなっているのを修正しました。
  • 自動最大化でプレイヤーの描画が崩れてしまうのを修正しました。
  • マウスを外した時に隠れない事があるのをなるべく防ぐようにしました。
  • NicoNicoFavlist からの追加時に内容が保存されないのを修正しました。 (at 2009-12-20 6:45)

最大化時に隠れます

地味な変更ですが、Mac だとプレイリストがプレイヤーの上に来るため、白いプレイリストがニョッキリはみ出てるのが気になったので><

Safari4 + GreaseKit 対応

Safari4 + GreaseKit に対応しました。Safari 派の方も使えます!(Mac のみ)

でも最近は Google Chrome に心が揺れており、Google Chrome 拡張の開発を考えています (^o^) ウワキナボク

技術的なお話だと、Favlist と同じく localStorage でデータを保存します。あと E4X に対応していないため CSS は普通に文字列で書き直しました。うーん><

謝辞

怠慢な作者に代わって、コメント欄で活発にサポートをしてくださっている方々に感謝申し上げます。

ありがとうございます!!

Enjoy!

niconicofavlist.user.js ver 1.19

ニコニコ動画でマイリストの新着を知る Greasemonkey スクリプト をバージョンアップしました。

インストール: niconicofavlist.user.js (使い方

基本的に不具合修正、仕様変更のみで、機能追加は特にありません。(放置気味で申し訳ありません><)

変更点

  • 「新しい順に並べる」オプションを追加しました。
  • ニコニコ動画のHTML変更に対応しました。
    • 登録ボタンの表示位置を変更しました。
    • マイリスト画面にて、並び順やページ切り替え時に登録ボタンが消えてしまうのを修正しました。
    • プロフィール画面では、登録ボタンを表示しなくなりました。(投稿動画一覧画面には引き続き表示されます)
    • フォントサイズが大きくなっているのを修正しました。

「新しい順に並べる」オプションについて

1.18 までの仕様では、マイリスト画面の登録ボタンを押した際に、選んでいた並び順で favlist 上でも並ぶようになっていましたが、わかりづらいのと、いちいち選択するのは面倒なので、思い切って並び順は「登録日時順」のみで固定とする事にしました。

通常は登録日時が古いものから順に先頭から並びますが、「新しい順に並べる」にチェックを入れた場合は新しいものから先頭に並びます。

個人的にはこちらの方が並び順が一貫して使い易いんじゃないか、と思うのですが、「けしからん!」という方は遠慮なくコメントしてください><

2009-12-24 01:51 追記:ここでいう「並び順」というのは、マイリスト自体の並び順ではなく、マイリストの中身(=動画)の並び順の話です。混乱させてしまい申し訳ないです><

Enjoy!

ざっくり Google Wave (1)

★ この説明は Google Wave Federation Protocol の Draft Protocol Spec (June 8, 2009) を読んで、僕なりに噛み砕いたものです。感覚をつかむ事を目的としているので、説明には間違いや不正確な部分があるかもしれません。ご了承ください。

Wave ≒ Mail

ツールとしての「メール」は現役ですが、古い技術です。Google は、この「メール」をもっとマシなものにできないかと考えて、この「Google Wave」を生み出しました。

Google が定義した取り決め*1では、Wave サービス をユーザーに提供する Wave プロバイダ(または Wave サーバー)が存在します。これは、メールサービス を提供する メールサーバー と似ています。

ユーザーはそれぞれ、Wave プロバイダからもらった Wave アドレス を持っています。これは jane@nicewave.com のように、メールアドレスと全く同じものです。nicewave.com の部分が、Wave プロバイダのドメインです。

Wave プロバイダは誰でも立ち上げる事ができます。Google が新サービスとして始める Google Wave は、Gmail のように単なる Wave プロバイダであり、それに便利なUIをくっつけたものです。*2しかし、Google はこの Wave プロバイダ間でやりとりするための取り決めや、開発者が利用できる API なども含めて Google Wave と呼んでいるようです。

Wave ≠ Mail

このように、旧来のメールそっくりな Google Wave ですが、違うところもあります。

まず、メールはやりとりしません。Google Wave では、皆で1つの文書に対して、あーでもないこーでもないと書き込みをしていきます。それだけだと、ただの掲示板と大した違いがありません。ここからが Google Wave のすごいところ。

他の人たちの書き込みが、見ているだけで、リアルタイムに更新されていったらどうなるでしょう?

それはつまり、届いた内容が次々に表示されていって、こちらが返信を書くと即座に相手にも伝わるという事です。まるでチャットをしているような迅速なやりとりができます。

では、Google Wave はチャットなのでしょうか?

かなり近いのですが、チャットではありません。文書に対しての書き込みは全てサーバーに保存されて、相手がオンラインでもオフラインでも関係ありませんし、チャットでは文書を作る事は出来ません。

みんなが編集する文書の集まりを、Wave (ウェーブ)と呼びます。逆にいえば、みんな Wave の上でやりとりをするわけです。


Wave の中身

Wave の中身を見てみましょう。

Wave の中には、「会話の単位」となる Wavelet (ウェーブレット)が集まっています。実際には、ユーザーは Wavelet を読み書きします。

Wavelet の中には、その会話(または文書の編集)に参加しているユーザーのリストがあります。参加者しか Wavelet を読み書きする事はできません。

また、Wavelet は他にも、みんなが編集している文書の中身をあらわす ドキュメント を持っています。この実体は XML 文書です*3

Wave と Wavelet の区別について、疑問に思う方もいらっしゃるでしょう。Wavelet の参加者は、同じ Wave 内に新たに自分専用の Wavelet を作る事ができます。自分専用なので、他の参加者は許可されない限り Wavelet の内容を読み書きできません。

これだけだと何のことかわかりませんね。例えば、インスタントメッセンジャーを使って、複数人でチャットしている様子を思い浮かべて下さい。ある参加者だけに、こっそりと伝えたい事があったらどうするでしょう? その参加者だけとの間で、新たに会話を始めますよね? あなたが今新しく始めたのが Wavelet です :)

Wave と Wavelet の管理者

Wave も Wavelet も、それを作ったユーザーが所属している Wave プロバイダ上で作られます。例えば、ユーザー jane@nicewave.com が新しく Wave を作ると、その Wave は nicewave.com によって管理されます。*4

では、nicewave.com によって管理されている Wave に、ユーザー me@mywave.com が参加して、Wavelet を新しく作るとどうなるでしょうか? その Wavelet は、今度は mywave.com によって管理される事になります。*5

つまり、Wave と Wavelet を管理する Wave プロバイダは、違う場合があるわけです。

管理するということ

「管理する」というのは、「オリジナルを持っている」という意味です。

文書を編集するためには、文書の内容を知る必要があります。自分が所属している Wave プロバイダが、文書を 管理 していれば、特に問題はありません。

ただ、他の Wave プロバイダが管理する文書の場合はどうでしょう?

文書を読むには、インターネット越しにダウンロードしてくる必要があります。それはつまり、文書の「コピー」を作っている事になります。コピーを持っておけば、わざわざ同じ文書を読む度にダウンロードする必要がありません。

このように、他の Wave プロバイダが持つ文書を読み書きする場合、一旦、自分の Wave プロバイダに文書のコピーを作り、それに対して読み書きする事になります。*6


Google Wave のスゴい所

Google Wave のスゴい所は何でしょう?

それは、1つの文書を、ネットワークをまたいで、みんなで一斉に編集できるところです。

1つの文書をみんなで編集するといえば Wiki があります。あまり経験がないかもしれませんが、Wiki の1ページを編集して保存しようとすると、他の人が同じページを編集していてエラーが出てしまう事があります。

同じファイルをみんなで編集しても、普通はお互いの修正を上書きしてしまいます。みんなで1つのものを編集するのは、簡単なようでとても難しいのです。ましてや、ネットワーク越しともなれば……。

そこで Google は考えました。

Operational Transformation

文書を作るには、以下のように、文字を入力したり消したりして進めていきます。

  1. Aを書く
  2. Bを書く
  3. Cを書く
  4. Bを消す
  5. Dを書く

逆に言えば、この一連の操作の流れと同じように文字を書き消しすれば、同じ文書を作る事ができるわけです。という事は、一連の操作を保存しておけば、いつでも同じ文書を再現できる事になります。

Wave プロバイダは、文書の内容ではなく、この一連の操作を保存しているのです。

誰かが文書に「Aを書く」と、Wave プロバイダは「Aを書く」を一連の操作に追加します。また、同時に他の Wave プロバイダにも「Aを書く」という操作を伝えます。*7すると、その Wave プロバイダ上のユーザー達に「Aが書かれた」事がリアルタイムに伝わるのです。

では、誰かが「Aを書く」のと同時に、他の人が「Bを書く」とどうなるでしょうか? 同時に編集しているので、そういう事もよく起こります。

XYZ

というテキストに対して

  • 「2文字目の前に A を書く」(XAY にするつもりで)
  • 「3文字目の前に B を書く」(YBZ にするつもりで)

という操作がある時、これらを順番に実行すると

XABYZ

となってしまい、「YBZ」にするつもりだった人は、思った位置に書けなかった事になってしまいます。

そこで登場するのが Operational Transformation 、直訳すると「操作の変換」という技術です(略して OT)。この技術を使うと、操作を矛盾のないように変換する事ができます。

  • 「2文字目の前に A を書く」(XAY にするつもりで)

という操作は特に変換をかけずにそのまま行います。

XAYZ

その次の

  • 「3文字目の前に B を書く」(YBZ にするつもりで)

という操作は、OT によって変換され

  • 「4文字目の前に B を書く」(YBZ にするつもりで)

となります。結果として

XAYBZ

となって、両者とも思った位置に書き込めた事になります。

このように OT を使うと、みんなが一斉に書き込んでも、出来る限り矛盾のないように一連の流れに変換する事ができるというわけです。*8

Google のスゴい所

実は Operational Transformation は10年以上も昔から研究されている技術です。

Google のスゴい所は、古くからある JavaScriptAjax という付加技術と組み合わせる事で Google Suggest というサービスにアレンジしたように、昔からある技術の価値を見抜き、現代風にアレンジしてしまう力なのだと思います。

メールが Google Wave としてアレンジされたように :)

*1:この取り決め (=Google Wave Federation Protocol) は、あくまでも「こんなのはどうだ」という下書きであり、仕様はオープンな場で議論により決定されている最中です。

*2:Comet や HTML5 を使ったフロントエンドはとても挑戦的で魅力的です。

*3:実際には XML 文書だけではなく、部分テキストの色などの装飾、ハイパーリンクなどを表現するための「スタンドオフアノテーション」と呼ばれる情報も持っています

*4:Wave には、それを識別するために Wave id という名前がつけられています。例えば nicewave.com$abc123 という Wave id だったら、nicewave.com によって管理されていて abc123 というIDを持つ Wave を指しています。

*5:Wavelet にも同様に、Wavelet id という名前がつけられています。例えば mywave.com/nicewave.com$abc123/xyz987 という Wavelet id だったら、mywave.com によって管理されている xyz987 というIDを持つ Wavelet があり、nicewave.com$abc123 という Wave に所属している事がわかります。Wave と Wavelet を同じ Wave プロバイダが管理している場合、mywave.com/abc123/xyz987 のように Wave id のドメイン部分と '$' が省略されます。

*6:逆に言えば、必要なければ他の Wave プロバイダには送信されないので、同一 Wave プロバイダ上での会話が他のプロバイダに漏れる事はありません。

*7:この時、プロバイダのサーバー間では XMPP というプロトコルが使われます。Google TalkJabber などのインスタントメッセンジャーで使われている通信方法です。

*8:もうちょっと技術的に言えば、排他ロックやトランザクション処理の必要がなくなるため、1つ1つの更新をとても高速に行う事ができます