173
Firefox Add-on SDK入門 Pasta-K [email protected]

Firefox Add-on SDK 入門

Embed Size (px)

Citation preview

Page 1: Firefox Add-on SDK 入門

Firefox Add-on SDK入門Pasta-K

📧[email protected]

Page 2: Firefox Add-on SDK 入門

こんにちは😺

Page 3: Firefox Add-on SDK 入門

こんにちは😺

で、誰?

Page 4: Firefox Add-on SDK 入門

🍣 KMCでの活動

KMC 37代目 広報

OSC Kyoto 2014 出展 etc

JavaScriptで世界平和2014

Page 5: Firefox Add-on SDK 入門

🍣 インターネット活動

! twitter.com/pastak id: Pasta-K pastak.hatenablog.com pastak-diary.hatenadiary.com " github.com/pastak

Page 6: Firefox Add-on SDK 入門

はてなインターン 2013

アルバイトエンジニア ←イマココ

Page 7: Firefox Add-on SDK 入門
Page 8: Firefox Add-on SDK 入門

最近では、はてなのインターンを経てウチへ来るというのが定番の

ようになっているんです !

休学して社員となった杉本氏をはじめ、現在5人いる学生アルバイトのメンバーも、そのほとんどが「京大マイコンクラブ」の所属。

Page 9: Firefox Add-on SDK 入門
Page 10: Firefox Add-on SDK 入門
Page 11: Firefox Add-on SDK 入門

アニメファン

Page 12: Firefox Add-on SDK 入門
Page 13: Firefox Add-on SDK 入門

🐾目次

• Mozilla Firefox について • ブラウザー拡張について • Firefox Add-on SDKでアドオンを作ってみる

Page 14: Firefox Add-on SDK 入門

" サンプルコード

https://github.com/pastak/firefox-addon-sdk-sample

Page 15: Firefox Add-on SDK 入門

Mozilla Firefoxについて

Page 16: Firefox Add-on SDK 入門

About Mozilla Firefoxhttps://www.mozilla.org/firefox/ Mozillaによって提供されているブラウザ

Win / Mac / Linux / Android 現行最新バージョン 36.0.1 (2015/03/05)

次回37は2015/03/31にリリース予定

Netscapeがうにゃむにゃみたいな歴史に興味がある人は自力でググッてください

Page 17: Firefox Add-on SDK 入門

ブラウザシェア (2015/02)

http://news.mynavi.jp/news/2015/03/04/084/

Page 18: Firefox Add-on SDK 入門
Page 19: Firefox Add-on SDK 入門

Page 20: Firefox Add-on SDK 入門
Page 21: Firefox Add-on SDK 入門

iceweasel

Page 22: Firefox Add-on SDK 入門

iceweasel

Iceweasel(アイスウィーズル)とは、ウェブブラウザ。またはその開発プロジェクト。Mozilla Firefox とほぼ同一のものであるが、商標の関係により同プロジェクトから独立したもの。 Debian によるものと、GNU によるもの(GNU IceWeasel)が存在したが、現在では GNU IceWeasel は GNU IceCat に名称変更されている。

http://ja.wikipedia.org/wiki/Iceweasel

Page 23: Firefox Add-on SDK 入門

ブラウザ拡張 現状確認

Page 24: Firefox Add-on SDK 入門

Google Chrome Opera

(Based Chromium)

Page 25: Firefox Add-on SDK 入門

Google Chrome / OperaJavaScript + HTML + CSS で書ける

Chromium由来の共通のAPIを利用する

→同じExtensionがそのまま動作する

Chrome ExtensionをOperaにインストールするための拡張

https://addons.opera.com/ja/extensions/details/download-chrome-extension-9 ちなみにOpera側のドキュメントの方が少しだけ充実してる

!ExtensionとAppの2種類がある

Page 26: Firefox Add-on SDK 入門

Safari

Page 27: Firefox Add-on SDK 入門

Safarihttps://extensions.apple.com/ Chromiumと同じくHTML + JS + CSSで書ける 大体同じ世界観で書ける ドキュメント https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/Introduction/Introduction.html !

Page 28: Firefox Add-on SDK 入門

Internet Explorer

Page 29: Firefox Add-on SDK 入門

Internet Explorer

MSDNにチュートリアルなどのページがある。(寧ろそれ以外どこにも載ってない) Browser Extensions Overviews and Tutorials https://msdn.microsoft.com/en-us/library/aa753616%28v=vs.85%29.aspx C#で書くっぽい。 あんまり書いてる人見たこと無い気がする

Page 30: Firefox Add-on SDK 入門

Mozilla Firefox

Page 31: Firefox Add-on SDK 入門

Mozilla Firefoxダウンロード https://addons.mozilla.org/ ドキュメントはとにかくMDN

https://developer.mozilla.org/ja/docs/Extensions 開発手法は2通り

XULベースのAdd-on

HTML + JS + CSSベースのAdd-on

Addon SDKで開発できるのは後者 このあと詳しく

Page 32: Firefox Add-on SDK 入門

Google Chrome VS

Mozilla Firefox

Page 33: Firefox Add-on SDK 入門

操作可能範囲

Page 34: Firefox Add-on SDK 入門
Page 35: Firefox Add-on SDK 入門
Page 36: Firefox Add-on SDK 入門

表示領域 右上ポップアップ オムニバー

Page 37: Firefox Add-on SDK 入門
Page 38: Firefox Add-on SDK 入門
Page 39: Firefox Add-on SDK 入門

表示領域 サイドバー ツールバー URLバー ポップアップ ステータスバー

Page 40: Firefox Add-on SDK 入門

表示領域 サイドバー ツールバー URLバー ポップアップ ステータスバーAdd-on SDKでステータスバーにボタンなど

を追加するためのwidgetモジュールがFirefox 29で削除

Page 41: Firefox Add-on SDK 入門

公開方法

Page 42: Firefox Add-on SDK 入門
Page 43: Firefox Add-on SDK 入門

https://chrome.google.com/webstore/

Page 44: Firefox Add-on SDK 入門

無審査 開発者登録に$5

Page 45: Firefox Add-on SDK 入門
Page 46: Firefox Add-on SDK 入門

https://addons.mozilla.org/

Page 47: Firefox Add-on SDK 入門

審査あり 開発者登録無料

Page 48: Firefox Add-on SDK 入門

審査あり 開発者登録無料

人が確認するのではない セキュリティ上の問題などを自動確認

Page 49: Firefox Add-on SDK 入門

💖

Page 50: Firefox Add-on SDK 入門

Firefox Add-on SDK について

Page 51: Firefox Add-on SDK 入門

改めてFirefoxのアドオンについて

XULベースの開発とAdd-on SDKでの開発

配布形式は xpi ( その正体はzip )

!

開発に関しては困ったらとにかくMDNを見る

https://developer.mozilla.org/ja/docs/Extensions

Page 52: Firefox Add-on SDK 入門

http://www.slideshare.net/skeevs/mozilla-firefox-extension-development

Page 53: Firefox Add-on SDK 入門

XULベースの開発についてこれ以降は特に触れない Firefoxの初期からあった伝統的な方

FirefoxアプリケーションのXULを上書きして機能を提供したり、XPCOM コンポーネントを通じて操作をしたりする。 !より詳細な比較は https://developer.mozilla.org/en-US/

Add-ons/SDK/Guides/SDK_vs_XUL を

Page 54: Firefox Add-on SDK 入門
Page 55: Firefox Add-on SDK 入門

2009年 Jetpackリリース

アドオンとして提供開始 当時JSだけでFirefoxのアドオンが作れると話題に

XULとか触らなくて良い

JSとHTMLとCSSでなんとかなる

jQueryも標準装備

Firebugでデバッグ出来る!

Page 56: Firefox Add-on SDK 入門

大喜び

Page 57: Firefox Add-on SDK 入門
Page 58: Firefox Add-on SDK 入門

– https://developer.mozilla.org/ja/docs/Jetpack

“Jetpack で、開発者は拡張機能を高速に作り出すことができると同時に、強化された体験を与えられたユーザーは、Web

とのふれあいが変わるでしょう。”

Page 59: Firefox Add-on SDK 入門

それから2010年 初頭

Jetpack(Prototype)から Jetpack Rebootへ

アドオンからSDKへ移行

開発環境もPythonで書かれたコマンドラインツールに

https://dev.mozilla.jp/2010/03/shifting-from-jetpack-ptototype-to-jetpack-reboot/ !

2010年末名称を Add-on SDK へ名称変更 🎉

Page 60: Firefox Add-on SDK 入門

Add-on SDKについて

FirefoxだけではなくThumderbird向けのアドオンも作れる 一部のAPIはAndroid向けのFirefoxにも対応

デバッグのためにUSBでインストール可能

Page 61: Firefox Add-on SDK 入門

Add-on SDKで扱えるAPI一覧

Page 62: Firefox Add-on SDK 入門

座学 ここまで

Page 63: Firefox Add-on SDK 入門

ここから 実践編

Page 64: Firefox Add-on SDK 入門

とにかく 数が多い

Page 65: Firefox Add-on SDK 入門

スライドに書いてあること一覧

Page 66: Firefox Add-on SDK 入門

ボタンを出す バッジを操作する パネルを出す サイドバーを出す 通信する その他諸々

Page 67: Firefox Add-on SDK 入門

🚀

Page 68: Firefox Add-on SDK 入門

Add-on SDKのインストールMac OSXの人はhomebrewで一発

!

Git cloneでも入手可

!

!

https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Installation

$ brew install mozilla-addon-sdk

$ git clone [email protected]:mozilla/addon-sdk.git

Page 69: Firefox Add-on SDK 入門

Add-on SDKのインストールhomebrew以外の方法で入れた場合は

./bin/ をPATHに追加する と使えるようになる。 SDK仮想環境をシェル上で起動することが一応推奨されているっぽい

$ bash ./bin/activate $ cfx --version Add-on SDK 1.17(12f7d53e8b5…)

Page 70: Firefox Add-on SDK 入門

cfxコマンドの基本的な使い方

Add-onのスケルトンを生成

!

Add-onをFirefox上で実行

!

Add-onをxpiとして生成

!

テストを実行

$ cfx init

$ cfx run

$ cfx xpi

$ cfx test

Page 71: Firefox Add-on SDK 入門

Add-on用のスケルトンを生成

!

!

!

!

!

この状態で      で実行可能 (ただし機能は何もない)

$ cfx init

. ├── data ├── lib │   └── main.js ├── package.json └── test └── test-main.js

$ cfx run

Page 72: Firefox Add-on SDK 入門

$ cfx init $ mkdir firefox-addon-sample // cfx initは空のディレクトリでのみ実行可能 $ cd firefox-addon-sample $ cfx init * lib directory created * data directory created * test directory created * generated jID automatically: ********* * package.json written * test/test-main.js written * lib/main.js written !Your sample add-on is now ready. Do "cfx test" to test it and "cfx run" to try it. Have fun!

Page 73: Firefox Add-on SDK 入門

これを実行するとFirefoxが立ち上がる

実行する度にprofileを生成する

普段の環境を汚さない

profileを指定する場合は

$ cfx run

$ cfx run -p <ProfilePath><ProfilePath> Mac OSXの場合は~/Library/Application Support/Firefox/Profiles/以下にある https://support.mozilla.org/ja/kb/profiles-where-firefox-stores-user-data

Page 74: Firefox Add-on SDK 入門

デバッグについて

JSで console.log すると標準出力に出る デバッガーも利用可能 about:addons で [デバッグ]ボタンを押す

Page 75: Firefox Add-on SDK 入門

配布用のxpiファイルを生成

ドラッグアンドドロップでインストール 自前サーバで配布する場合でもアップデートを配信することも出来る !!!!HTTPで配信する場合はこの方法では署名できない

詳細: Add-on SDKで作ったFirefox拡張をHTTPで配布、アップデートする方法 - Pastalablog in はてな

http://pastak.hatenablog.com/entry/2013/10/03/213040 !※AMO以外からは配布出来なくなる予定があるので注意(おまけ参照)

$ cfx xpi

$ cfx xpi \ --update-url=https://hogehoge.com/hoge.update.rdf \ --update-link=https://hogehoge.com/hoge.xpi

Page 76: Firefox Add-on SDK 入門

ファイルの紹介. ├── data <- 静的htmlや画像ファイルなど │ アイコンなどもここに置く ├── lib │   └── main.js <- エントリーポイント │ になるJSファイル ├── package.json <- 設定などを書く └── test <- ここに置いておけば │ cfx test で実行してくれる └── test-main.js

Page 77: Firefox Add-on SDK 入門

package.jsonAdd-onに関する情報を書いておくファイル。

$ cat package.json { "name": "sample", "title": "sample", "id": "jid1-ZaoDi2iCqJeZVg", "description": "a basic add-on", "author": "", "license": "MPL 2.0", "version": "0.1" }

Page 78: Firefox Add-on SDK 入門

package.jsonname: アドオンの名前を入れる。

ドット(.)やスペースを含むことが出来ない。

title や fullName があればそちらが利用される

version: アドオンのバージョンを書く。

記法は npm などと同じくsemver に準拠する

http://semver.org/

Page 79: Firefox Add-on SDK 入門

package.jsonpermissions: クロスドメインXHRを許可するホスト名の指定

private browsing mode での許可

icon, icon64: アイコンのパスを指定する

iconは48x48、icon64は64x64

無ければデフォルトアイコンを利用する

Page 80: Firefox Add-on SDK 入門

main.js を編集してみる

右上にボタンを追加してみる

Page 81: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick }); !function handleClick(state) { tabs.open("http://www.mozilla.org/"); }

Page 82: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick }); !function handleClick(state) { tabs.open("http://www.mozilla.org/"); }

モジュールを読み込む モジュールの実体は build時にxpiに含まれる

Page 83: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick }); !function handleClick(state) { tabs.open("http://www.mozilla.org/"); }

モジュールのパス

Page 84: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick }); !function handleClick(state) { tabs.open("http://www.mozilla.org/"); }

ボタンにidとか アイコンとか ハンドラを設定する。

Page 85: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick }); !function handleClick(state) { tabs.open("http://www.mozilla.org/"); }

相対パスで書くと ./data以下を参照する

Page 86: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick }); !function handleClick(state) { tabs.open("http://www.mozilla.org/"); }

ツールバー 18x18 (px) メニューパネル 32x32 (px)

Page 87: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick }); !function handleClick(state) { tabs.open("http://www.mozilla.org/"); }

ツールバー 18x18 (px) メニューパネル 32x32 (px)

Page 88: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: "./icon-16.png", onClick: handleClick }); !function handleClick(state) { tabs.open("http://www.mozilla.org/"); }

省略可

Page 89: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick }); !function handleClick(state) { tabs.open("http://www.mozilla.org/"); }

クリック時に呼ばれる関数

Page 90: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick }); !function handleClick(state) { tabs.open("http://www.mozilla.org/"); } 新しいタブを開く

Page 91: Firefox Add-on SDK 入門

badgeを出すNew feature for Firefox 36

Page 92: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !function handleClick(state) { button.badge = state.badge + 1; }

Page 93: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !function handleClick(state) { button.badge = state.badge + 1; }

変更箇所

Page 94: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !function handleClick(state) { button.badge = state.badge + 1; }

badgeの値と色を指定 値: Number or String 色: CSS color value

Page 95: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick, badge: "KMC!!", badgeColor: "#00AAAA" }); !function handleClick(state) { button.badge = state.badge + 1; }

Page 96: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick, badge: "KMC!!", badgeColor: "blue" }); !function handleClick(state) { button.badge = state.badge + 1; }

Page 97: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var tabs = require("sdk/tabs"); !var button = buttons.ActionButton({ id: "mozilla-link", label: "Visit Mozilla", icon: { "16": "./icon-16.png", "32": "./icon-32.png", "64": "./icon-64.png" }, onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !function handleClick(state) { button.badge = state.badge + 1; } badgeの値を変更

Page 98: Firefox Add-on SDK 入門

ボタンを押したらパネルが出る

Page 99: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var panels = require("sdk/panel"); !var button = buttons.ActionButton({ id: "panel-sample", label: "Panel Button", icon: "./icon-16.png", onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !var panel = panels.Panel({ contentURL: "./panel.html", onHide: function(){ button.state('window', {checked: false}); } }); !function handleClick(state) { if (!state.checked) { panel.show({ position: button }); } button.state('window', {checked: !state.checked}); }

panelモジュール

main.js

Page 100: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var panels = require("sdk/panel"); !var button = buttons.ActionButton({ id: "panel-sample", label: "Panel Button", icon: "./icon-16.png", onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !var panel = panels.Panel({ contentURL: "./panel.html", onHide: function(){ button.state('window', {checked: false}); } }); !function handleClick(state) { if (!state.checked) { panel.show({ position: button }); } button.state('window', {checked: !state.checked}); }

パネルを記述

main.js

Page 101: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var panels = require("sdk/panel"); !var button = buttons.ActionButton({ id: "panel-sample", label: "Panel Button", icon: "./icon-16.png", onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !var panel = panels.Panel({ contentURL: "./panel.html", onHide: function(){ button.state('window', {checked: false}); } }); !function handleClick(state) { if (!state.checked) { panel.show({ position: button }); } button.state('window', {checked: !state.checked}); }

width, height 大きさ contextMenu コンテキストメニューの表示の許可 onShow / onHide / onMessage 各々のイベントハンドラー main.js

Page 102: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var panels = require("sdk/panel"); !var button = buttons.ActionButton({ id: "panel-sample", label: "Panel Button", icon: "./icon-16.png", onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !var panel = panels.Panel({ contentURL: "./panel.html", onHide: function(){ button.state('window', {checked: false}); } }); !function handleClick(state) { if (!state.checked) { panel.show({ position: button }); } button.state('window', {checked: !state.checked}); }

表示するHTMLファイルを指定

main.js

Page 103: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var panels = require("sdk/panel"); !var button = buttons.ActionButton({ id: "panel-sample", label: "Panel Button", icon: "./icon-16.png", onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !var panel = panels.Panel({ contentURL: "./panel.html", onHide: function(){ button.state('window', {checked: false}); } }); !function handleClick(state) { if (!state.checked) { panel.show({ position: button }); } button.state('window', {checked: !state.checked}); }

パネルを表示

main.js

Page 104: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var panels = require("sdk/panel"); !var button = buttons.ActionButton({ id: "panel-sample", label: "Panel Button", icon: "./icon-16.png", onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !var panel = panels.Panel({ contentURL: "./panel.html", onHide: function(){ button.state('window', {checked: false}); } }); !function handleClick(state) { if (!state.checked) { panel.show({ position: button }); } button.state('window', {checked: !state.checked}); }

object top / bottom / left / right

main.js

Page 105: Firefox Add-on SDK 入門

var buttons = require('sdk/ui/button/action'); var panels = require("sdk/panel"); !var button = buttons.ActionButton({ id: "panel-sample", label: "Panel Button", icon: "./icon-16.png", onClick: handleClick, badge: 0, badgeColor: "#00AAAA" }); !var panel = panels.Panel({ contentURL: "./panel.html", position: button, onHide: function(){ button.state('window', {checked: false}); } }); !function handleClick(state) { if (!state.checked) { panel.show(); } button.state('window', {checked: !state.checked}); }

ここで設定しておいてもOK

main.js

Page 106: Firefox Add-on SDK 入門

パネル内のイベントを掴む

パネル内のHTML上のボタンが押されたらbadgeの内容をアップデートする

Page 107: Firefox Add-on SDK 入門

Messaging(1) - port emit(name, message) on(name, handler) removeListener(name, handler) once(name, handler) 一度だけmessageを受ける

事前にmessageに対してhandlerを設定しておく

https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Content_Scripts/using_port

Page 108: Firefox Add-on SDK 入門

Messaging(2) - postMessage

messageイベントを発火させる

context-menuモジュールなどはportがサポートされていないのでこちらを使うしかない panelなどには onMessage があるので、こっちを使っておくと吉

https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Content_Scripts/using_postMessage

Page 109: Firefox Add-on SDK 入門

!!var panel = panels.Panel({ contentURL: "./panel.html", onHide: function(){ button.state('window', {checked: false}); }, onMessage: function(){ button.badge = button.badge + 1; } }); !

main.js(抜粋)

Page 110: Firefox Add-on SDK 入門

!!var panel = panels.Panel({ contentURL: "./panel.html", onHide: function(){ button.state('window', {checked: false}); }, onMessage: function(){ button.badge = button.badge + 1; } }); !

メッセージを受取ったら badgeを++

main.js(抜粋)

Page 111: Firefox Add-on SDK 入門

<h1>Panel!!!!!!!</h1> <button id='increament'>++</button> <script> !!!</script>

var btn = document.getElementById('increament'); btn.addEventListener('click', function(){ addon.postMessage("increament"); })

./data/panel.html

この場合はpostMessageは addonのメソッド JSをcontentScriptとして 読み込ませた場合はselfのメソッドになる

Page 112: Firefox Add-on SDK 入門

var btn = document.getElementById('increament'); btn.addEventListener('click', function(){ addon.postMessage({ type: 'increament' }); }) var color = document.getElementById('color'); color.addEventListener('change', function(){ addon.postMessage({ type: 'color', value: color.value }); })

<h1>Panel!!!!!!!</h1> <button id='increament'>++</button> <input type='color' id='color'/> <script> !!!!!!!!!!!!</script>

./data/panel.html

input[type=color]を使って badgeの色を変える

Page 113: Firefox Add-on SDK 入門

var btn = document.getElementById('increament'); btn.addEventListener('click', function(){ addon.postMessage({ type: 'increament' }); }) var color = document.getElementById('color'); color.addEventListener('change', function(){ addon.postMessage({ type: 'color', value: color.value }); })

<h1>Panel!!!!!!!</h1> <button id='increament'>++</button> <input type='color' id='color'/> <script> !!!!!!!!!!!!</script>

./data/panel.html

messageはJSONserializeされる

Page 114: Firefox Add-on SDK 入門

var panel = panels.Panel({ contentURL: "./panel.html", onHide: function(){ button.state('window', {checked: false}); }, onMessage: function(message){ switch(message.type){ case 'increament': button.badge = button.badge + 1; break; case 'color': button.badgeColor = message.value; break; } } });

main.js(抜粋)

message.typeで挙動を切替

Page 115: Firefox Add-on SDK 入門

サイドバーを表示する

Page 116: Firefox Add-on SDK 入門

サイドバー

Chrome Extensionだとこれが出来ない

扱い方の要領はpanelと同じ

Page 117: Firefox Add-on SDK 入門

sideBar = require("sdk/ui/sidebar").Sidebar({ id: 'sample-sidebar', title: 'MiracleSidebar', url: './sidebar.html' })

main.js

Page 118: Firefox Add-on SDK 入門

sideBar = require("sdk/ui/sidebar").Sidebar({ id: 'sample-sidebar', title: 'MiracleSidebar', url: './sidebar.html' })

main.js

Page 119: Firefox Add-on SDK 入門

main.js

sideBar = require("sdk/ui/sidebar").Sidebar({ id: 'sample-sidebar', title: 'MiracleSidebar', url: './sidebar.html', onAttach: function(worker){ worker.port.emit('ping', ''); } })

Page 120: Firefox Add-on SDK 入門

main.js

sideBar = require("sdk/ui/sidebar").Sidebar({ id: 'sample-sidebar', title: 'MiracleSidebar', url: './sidebar.html', onAttach: function(worker){ worker.port.emit('ping', ''); } }) サイドバーが表示されたら

messageを送る

Page 121: Firefox Add-on SDK 入門

<script> !!!</script>

addon.port.on('ping', function(){ alert('pong'); })

./data/sidebar.html

Page 122: Firefox Add-on SDK 入門

<script> !!!</script>

addon.port.on('ping', function(){ alert('pong'); })

./data/sidebar.html

alertを出す

Page 123: Firefox Add-on SDK 入門

サイドバーでAjaxを実装する

サイドバーからはCross-Originの制約でXHRなどで外部に通信できない panelなどはJSをファイルに分けて、

contentScriptFileなどで読込めばXHR出来る

→main.jsで代わりに通信して結果を

 messageで送信する

Page 124: Firefox Add-on SDK 入門

package.jsonに追記通信先のプロトコルとドメインを記述する Wildcardは使えないので注意

"permissions": { "cross-domain-content": [ "http://example.org/", "https://example.com/" ] }

Page 125: Firefox Add-on SDK 入門

Request = require("sdk/request").Request; sideBar = require("sdk/ui/sidebar").Sidebar({ id: 'sample-sidebar', title: 'MiracleSidebar', url: './sidebar.html', onAttach: function(worker){ Request({ url: "http://api.openweathermap.org/data/2.5/weather?q=Kyoto,jp", // 天気情報を取得するAPIを利用してみる onComplete: function(response){ worker.port.emit('ping', response.json) } }).get() } })

main.js

Page 126: Firefox Add-on SDK 入門

Request = require("sdk/request").Request; sideBar = require("sdk/ui/sidebar").Sidebar({ id: 'sample-sidebar', title: 'MiracleSidebar', url: './sidebar.html', onAttach: function(worker){ Request({ url: "http://api.openweathermap.org/data/2.5/weather? q=Kyoto,jp", // 天気情報を取得するAPIを利用してみる onComplete: function(response){ worker.port.emit('ping', response.json) } }).get() } })

main.js

外部と通信するために Requestモジュールを利用

Page 127: Firefox Add-on SDK 入門

RequestXMLHttpRequestをベースにしたオブジェクト

!

option: url: 通信先のURL

onComplete: 通信成功後に呼ぶ関数

content: GETやHEADのquery、POSTやPUTのbody

contentType: request headerのContent-Typeの内容

header: request header

require("sdk/request").Request(option)

Page 128: Firefox Add-on SDK 入門

Request methods

例: GET

!

get() head() post() put() delete()

require("sdk/request").Request(option).get()

Page 129: Firefox Add-on SDK 入門

Request = require("sdk/request").Request; sideBar = require("sdk/ui/sidebar").Sidebar({ id: 'sample-sidebar', title: 'MiracleSidebar', url: './sidebar.html', onAttach: function(worker){ Request({ url: "http://api.openweathermap.org/data/2.5/weather? q=Kyoto,jp", // 天気情報を取得するAPIを利用してみる onComplete: function(response){ worker.port.emit('ping', response.json) } }).get() } })

main.js

成功したらportで サイドバー内のJSに送る

Page 130: Firefox Add-on SDK 入門

Request = require("sdk/request").Request; sideBar = require("sdk/ui/sidebar").Sidebar({ id: 'sample-sidebar', title: 'MiracleSidebar', url: './sidebar.html', onAttach: function(worker){ Request({ url: "http://api.openweathermap.org/data/2.5/weather? q=Kyoto,jp", // 天気情報を取得するAPIを利用してみる onComplete: function(response){ worker.port.emit('ping', response.json) } }).get() } })

main.js

通信結果を保持しているオブジェクト text: plain text json: JSON.parse()の結果 status: status code ( ex: 200 ) statusText: headers: HTTP response headerのK/Vオブジェクト

Page 131: Firefox Add-on SDK 入門

<script> !!!!!!!!!!!</script>

addon.port.on('ping', function(data){ var weather = data.weather[0]; document.body.innerHTML = ` <ul> <li>Weather: ${weather.main}</li> <li>Description: ${weather.description}</li> <li>Sunrise: ${Date(data.sys.sunrise)} </li> <li>Sunset: ${Date(data.sys.sunset)}</li> </ul> `; })

./data/sidebar.html

Page 132: Firefox Add-on SDK 入門

<script> !!!!!!!!!!!</script>

addon.port.on('ping', function(data){ var weather = data.weather[0]; document.body.innerHTML = ` <ul> <li>Weather: ${weather.main}</li> <li>Description: ${weather.description}</li> <li>Sunrise: ${Date(data.sys.sunrise)} </li> <li>Sunset: ${Date(data.sys.sunset)}</li> </ul> `; })

./data/sidebar.html

メッセージを受け取って HTMLとして出力

Page 133: Firefox Add-on SDK 入門

諸々モジュール紹介

clipboard, context-menu, hotkeys, notification, page-mod, simple-prefs …

Page 134: Firefox Add-on SDK 入門

clipboard

var clipboard = require("sdk/clipboard"); clipboard.set("KMC is great!"); var contents = clipboard.get(); //set some HTML clipboard.set("<marquee>KMC KMC KMC</marquee>", "html");

Page 135: Firefox Add-on SDK 入門

context-menu

コンテキストメニューを表示する Chromeと違って細やかに設定できる

Page 136: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

Page 137: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

メニューアイテム を生成

Page 138: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

表示するテキスト

Page 139: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

アイコンを出すことも 出来る

Page 140: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

表示するコンテキストを 指定する

Page 141: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

こういう指定も出来る

Page 142: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

PreficateContextは 引数の関数がtrueを返す場合に メニューアイテムを表示する

Page 143: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

PreficateContextは 引数の関数がtrueを返す場合に メニューアイテムを表示する

Page 144: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

documentType text/html, image/jpeg documentURL ページのURL targetName タグ名 targetID id属性 isEditable contenteditable? selectionText 選択中の文字列 srcURL <img>のsrc属性 linkURL <a>のhref属性 value <input><textarea>のvalue属性

Page 145: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

MenuはItemを 子に持つことが出来る

Page 146: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

ページ上のあらゆる箇所

Page 147: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

child, sp, child2を 子メニューとして持つ

Page 148: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

セパレータを生成

Page 149: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' }); 親メニューの無いアイテム

Page 150: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' });

メニューを表示している状態で このキーを押すと選択したことになる。 キーの組み合わせ不可

Page 151: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' }); URLでマッチさせる

Page 152: Firefox Add-on SDK 入門

var cm = require("sdk/context-menu"); var sp = cm.Separator(); var child = cm.Item({ label: "Child Item 2 show only on <img>", image: require("sdk/self").data.url("icon-16.png") }); child.context.add(cm.SelectorContext('img')); var child2 = cm.Item({ label: "This item show only on some context", context: cm.PredicateContext(function(context){ return ( (context.documentURL.match(/kmc/)) || (context.selectionText && context.selectionText.length > 3) || (context.srcURL && context.srcURL.match(/png$/)) ) }) }); var menu = cm.Menu({ label: "sample menu", context: cm.PageContext(), items: [child, sp, child2] }) var menu2 = cm.Item({ label: "Welcome KMC", accesskey: '1', context: cm.URLContext("*.kmc.gr.jp"), contentScriptFile: './welcome-kmc.js' }); 選択された際に実行されるJS

Page 153: Firefox Add-on SDK 入門

var { Hotkey } = require("sdk/hotkeys"); !var myPanel = require("sdk/panel").Panel({ ... }); !var showHotKey = Hotkey({ combo: "accel-shift-o", onPress: function() { myPanel.show(); } });

hotkeys

Page 154: Firefox Add-on SDK 入門

hotkeys

alt: [alt]、Macでは [option] キー

meta: [Meta] ([#] キー)、Macでは [⌘]

accel: [ctrl]、Macでは[⌘]

shift, control, pageup, pagedown

Page 155: Firefox Add-on SDK 入門

notificationvar notifications = require("sdk/notifications"); !notifications.notify({ title: "Mailer", text: "Got new 2 mails!", onClick: function(){ console.log('clicked') }, iconURL: "./myIcon.png" });

Page 156: Firefox Add-on SDK 入門

page-mod

user.jsなどのように閲覧しているページ内にJSを埋め込む。

content script と呼ばれることが多い

Page 157: Firefox Add-on SDK 入門

page-modvar pageMod = require("sdk/page-mod"); !pageMod.PageMod({ include: "*", exclude: "*.kmc.gr.jp", contentScriptFile: [ "./jquery-1.7.min.js", "./my-script.js" ] });

Page 158: Firefox Add-on SDK 入門

page-mod

content script 内で port や postMessage を使う場合は window.self のメソッドとして利用できる

Page 159: Firefox Add-on SDK 入門

simple-prefs

設定画面にボタンなどを配置する package.json に記述しておく

"preferences": [{ "name": "somePreference", "title": "Some preference title", "description": "description text", "type": "string", "value": "this is the default string value" }]

Page 160: Firefox Add-on SDK 入門

simple-prefstype: 種別を指定(後述)

name: JS内で利用するための名前

   (propaty name として valid な必要がある)

title: 設定画面でラベルに使われる

description: 設定に関する説明

hidden: 非表示にする ( boolean )

value: デフォルト値

Page 161: Firefox Add-on SDK 入門

simple-prefs値を取り出す時は name を使う

"preferences": [{ "name": "somePreference", "type": "string", "value": "this is the default string value" }]var preferences = require("sdk/simple-prefs").prefs; // Get console.log(preferences.somePreference); // Update preferences.somePreference = "this is a new value";

package.json

main.js

Page 162: Firefox Add-on SDK 入門

type (1)bool: <input type='checkbox'> boolint: checkbox が表示されるが値はT/Fではなくて on off の値が利用される

"preferences": [{ "type": "boolint", "on": "1", // value for true must be string "off": "2", // value for false must be string "value": 1 }]

Page 163: Firefox Add-on SDK 入門

type (2)

integer: <input type='number'> string: <input type='text'> color: <input type='color'> file: <input type='file'> フルパスを得る

directory: ディレクトリのパスを得る

Page 164: Firefox Add-on SDK 入門

type (3)menulist: ドロップダウンリストが表示される

radio: <input type="radio">{ "type": "menulist", // or "radio" "options": [ { "value": "0", //must be string "label": "nona" }, { "value": "1", "label": "prime" } ] }

Page 165: Firefox Add-on SDK 入門

type (4)control: <button> {

"type": "control", "label": "Click me!", "name": "sayHello", "title": "Say Hello" }

var sp = require("sdk/simple-prefs"); sp.on("sayHello", function() { console.log("hello"); });

package.json

main.js

Page 166: Firefox Add-on SDK 入門

type (4)control: <button> {

"type": "control", "label": "Click me!", "name": "sayHello", "title": "Say Hello" }

var sp = require("sdk/simple-prefs"); sp.on("sayHello", function() { console.log("hello"); });

package.json

main.js

Page 167: Firefox Add-on SDK 入門

type (4)control: <button> {

"type": "control", "label": "Click me!", "name": "sayHello", "title": "Say Hello" }

var sp = require("sdk/simple-prefs"); sp.on("", function() { console.log("hello"); });

package.json

main.js

空にすると全てのcontrollの clickを受け取る

Page 168: Firefox Add-on SDK 入門

まとめズサッと一気に Add-on SDK の世界観を紹介しました。

サンプルコードも用意したので、MDNなどと合わせて

上手く活用して良いAdd-onを作って下さい。

Firefoxをより便利にして 最高のインターネットライフを 手に入れよう😍😍😍😍

Page 169: Firefox Add-on SDK 入門

Do you have any questions?🙉

Page 170: Firefox Add-on SDK 入門

おまけ※時間が余った時など用

Page 171: Firefox Add-on SDK 入門

野良アドオンについて

Page 172: Firefox Add-on SDK 入門

公式配布サイト以外に関する対応Chrome 2014/05 から Windows 向けの Stable と

Beta チャンネルのみ外部サイトからインストールした Extension は無効化

Firefox AMO以外で配布する場合は要署名

Nightly と Developer Edition は除外http://googledevjp.blogspot.jp/2014/03/chrome-chrome.html https://dev.mozilla.jp/2015/02/extension-signing-safer-experience/

Page 173: Firefox Add-on SDK 入門

Firefoxにおける影響

アドオンのテストを行う場合はDeveloper Edition、Nightly あるいはいずれかのノーブランド版で行う必要がある。 AMOで配布しない場合も一度署名のために AMO へ拡張機能ファイルをアップロードするという必須手順が導入される。