GLOBAL-ALIGN::left
ALIGN::center
拡張機能
開発の
基礎知識
[[EM:Part3]]
----
CHAPTER::拡張機能開発のチュートリアル
チュートリアル
----
拡張機能を
実際に
作ってみる
----
CHAPTER::開発環境の整備
HEADER::拡張機能開発のチュートリアル
FOOTER::開発環境に必要なもの
ALIGN::center
開発環境に
必要なもの
----
[[EM:絶対に必要]]
・[テキストエディタ]
([UTF-8]を扱えるもの)
・[アーカイバ]
([ZIP形式]を扱えるもの)
[[EM:あると便利]]
・[JavaScript]デバッガ
----
テキスト
エディタ
----
秀丸エディタ
[[http://hide.maruo.co.jp/]]
TeraPad
[[http://www5f.biglobe.ne.jp/~t-susumu/]]
----
アーカイバ
----
7-Zip
[[http://www.7-zip.org/ja/]]
----
デバッガ
----
Venkman JavaScriptデバッガ
[[https://addons.mozilla.org/firefox/216/]]
[[(日本語パック)|https://piro.sakura.ne.jp/latest/blosxom.cgi/mozilla/extension/2005-09-30_venkman-ja.htm]]
----
ALIGN::center
しておくと
便利な設定
----
[コンソール]への
エラーメッセージ出力
----
[[PRE:
user_pref("browser.dom.window.dump.enabled", true);
]]
----
dump("文字列") という機能が使えるようになる
渡した文字列がコンソールに表示される
※Windows環境ではFirefoxを
-consoleオプション付きで起動する
LinuxやMac OS XではFirefoxを
ターミナルから起動する
----
エラーコンソールへの
内部エラーの表示
----
[[PRE:
user_pref("javascript.options.showInConsole", true);
]]
※「ツール」→「エラーコンソール」で
エラーコンソールを起動
----
次
----
FOOTER::拡張機能を実際に作ってみる
ALIGN::center
拡張機能を
実際に
作ってみる
----
拡張機能の
タイプ
----
主に
2種類
----
・新機能を加える物
・既存の機能の
挙動を変える物
----
CHAPTER::Close All Tabs
新機能を
加える
----
・ツールバーのボタン
・サイドバーのパネル
・それ以外
----
ツールバーボタンと
サイドバーパネルは
簡単に追加できる
----
なので
そこを解説
----
CHAPTER::Close All Tabs-Overview
FOOTER::拡張機能を実際に作ってみる - Close All Tabs
ALIGN::center
[[EM:Close All Tabs]]
「すべてのタブを一度に閉じる」
ボタンをツールバーに加えてみる
----
目標(要求仕様)
・ツールバーに「すべてのタブを閉じる」
ボタンを加える。
・ボタンを押すと、空のタブを残して
すべてのタブを閉じる。
・「すべてのタブを閉じる」という項目を
「ファイル」メニューの中にも加える。
・キーボードショートカット「Ctrl-Q」でも
機能を利用できるようにする。
----
作業手順
1. IDを決める
2. どこをいじればいいか調べる
3. フォルダとファイルを用意する
4. XULで構造を定義する
5. JavaScriptで挙動を定義する
6. CSSで外観を定義する
7. パッケージングする
8. 配布
----
用意するもの:
ボタン用アイコン画像
大サイズ 24×24 [[image src="icon.png" width="72" height="72"]]
小サイズ 16×16 [[image src="icon-small.png" width="48" height="48"]]
----
CHAPTER::Close All Tabs-ID
ALIGN::center
IDを決める
----
ID
----
拡張機能を
識別するための
一意な名前
----
使えるIDの形式
[[EM:UUID(GUID)]]:完全なID
{E0EACCD1-98F3-4936-A229-41C667E820B8}
[[EM:名前@ドメイン]]:簡易的なID
closealltabs@piro.sakura.ne.jp
----
UUIDの
作り方
----
Web上のサービスを
使うと楽チンです
[[http://kruithof.xs4all.nl/uuid/uuidgen]]
----
次
----
CHAPTER::Close All Tabs-Inspect
ALIGN::center
どこをいじれば
いいか調べる
----
ツールバーのボタンの追加の場合は
定型的な書き方だけでいけるので
特に調べなくてもよい
----
次
----
CHAPTER::Close All Tabs-Folder
ALIGN::center
フォルダと
ファイルを
用意する
----
プロファイル
フォルダの中に
拡張機能用の
フォルダを作る
----
|Windows XP/2000|C:\Documents and Settings\<ユーザ名>\Application Data
\Mozilla\Firefox\<プロファイル名>\extensions
|Windows NT|C:\WINNT\Profiles\<ユーザ名>\Application Data
\Mozilla\Firefox\<プロファイル名>\extensions
|Windows 98/ME|C:\Windows\Application Data
\Mozilla\Firefox\<プロファイル名>\extensions
|Mac OS X| ~/Library/Application Support
/Firefox/<プロファイル名>/extensions
|Linux| ~/.mozilla/firefox/<プロファイル名>/extensions
----
[[image src="03.jpg" width="319" height="600"]]
----
次
----
CHAPTER::Close All Tabs-XUL
ALIGN::center
XULで
構造を
定義する
----
closealltabs.xul
[[PRE:
]]
----
コマンド
の定義
----
コマンド
=他の要素からの
参照専用の要素
----
ボタンやメニューに
割り当てる機能は
まずコマンドで定義
----
[[PRE:
]]
----
ALIGN::center
command要素の属性
|属性|意味
|id|そのコマンドの名前(ID)
|oncommand|コマンドが呼ばれた時に
実行するスクリプト
----
ツールバー
ボタンの定義
----
Firefoxの
ツールバー
----
カスタマイズ
する時には
パレットから
ボタンを選ぶ
----
パレットの中に
ボタンを追加する
----
[[PRE:
]]
----
ALIGN::center
toolbarbutton要素の属性
|属性|意味
|label|ボタンの
ラベル文字列
|command|ボタンが押された時に
呼び出すコマンドのID
----
キーボード
ショートカット
----
AJAXなどでは
JavaScriptで
定義する
----
XULには専用の
要素がある
----
[[PRE:
]]
----
ALIGN::center
key要素の属性
|属性|意味
|key|反応する文字キー
アルファベットや記号など
|keycode|反応する特殊キー(キーコード)
VK_ENTER, VK_BACK_SPACEなど
|modifiers|アクセラレータキー
Control, Meta(Command),
Shift, Altまたはaccel
----
メニュー
項目
----
[[PRE:
]]
----
ALIGN::center
menuitem要素の属性
|属性|意味
|key|割り当てる
ショートカットのID
|insertafter|オーバーレイ時に
挿入位置の目印にする要素のID
|insertbefore|オーバーレイ時に
挿入位置の目印にする要素のID
|position|オーバーレイ時の
挿入位置(数値)
----
次
----
CHAPTER::Close All Tabs-JavaScript
ALIGN::center
JavaScript
で挙動を
定義する
----
closealltabs.js
[[PRE:
function BrowserCloseAllTabs() {
var tab = gBrowser.addTab('about:blank');
gBrowser.removeAllTabsBut(tab);
}
]]
----
gBrowserは
ブラウザ要素
()
への参照
----
ALIGN::center
tabbrowserのメソッド(一部)
|メソッド|引数|意味
|addTab()|開くページのURI|新しいタブを開く
|removeTab()|閉じる
タブの要素|タブを閉じる
|removeAllTabsBut()|閉じない
タブの要素|渡したタブ以外を
全て閉じる
----
次
----
CHAPTER::Close All Tabs-CSS
ALIGN::center
CSSで
外観を
定義する
----
closealltabs.css
[[PRE:
#closeAllTabs-button {
list-style-image: url(icon.png);
}
toolbar[iconsize="small"] #closeAllTabs-button {
list-style-image: url(icon-small.png);
}
#menuitem_closeAllTabs {
list-style-image: url(icon-small.png);
}
]]
----
XULにおける
list-style-image
=ボタンやメニュー項目の
アイコンの指定に使われる
----
次
----
CHAPTER::Close All Tabs-manifest
ALIGN::center
インストール
定義
----
install.rdf
[[PRE:
]]
----
ALIGN::center
名前空間「http://www.mozilla.org/2004/em-rdf#」のプロパティ
|名|値|名|値
|id|拡張機能や
アプリケーションのID|homepageURL|拡張機能の
ダウンロードページ
|name|表示名|iconURL|拡張機能マネージャに
表示するアイコン
|version|拡張機能の
バージョン番号|updateURL|更新情報を提供する
リソースのURI
|creator|作者の名前|targetApplication|インストール対象の
アプリケーション
|contributor|貢献者の名前
(いれば)|minVersion|インストール対象
アプリケーションの
最低バージョン
|description|簡単な説明文|maxVersion|インストール対象
アプリケーションの
最大バージョン
----
インストール対象
アプリケーション
----
これも
UUIDで指定
----
Firefox
{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
Thunderbird
{3550f703-e582-4d05-9a08-453d09bdfdc6}
----
ALIGN::center
マニフェスト
ファイル
----
chrome.manifest
[[PRE:
content closealltabs
chrome/content/closealltabs/
skin closealltabs
classic/1.0 chrome/skin/classic/closealltabs/
overlay chrome://browser/content/browser.xul
chrome://closealltabs/content/closealltabs.xul
overlay chrome://global/content/customizeToolbar.xul
chrome://closealltabs/content/closealltabs.xul
]]
----
ALIGN::center
|オペレータ|意味
|~content|~基本のリソースの登録
|~locale|~言語リソースの登録
|~skin|~テーマの登録
|overlay|オーバーレイの読み込み指定
|style|テーマの読み込み指定
----
次
----
CHAPTER::Close All Tabs-XPI
ALIGN::center
XPIパッケージを
作成する
----
[[image src="03.jpg" width="319" height="600"]]
----
この構造のまま
closealltabs@piro.sakura.ne.jp
以下をまとめて
closealltabs.[[EM:xpi]]
というファイル名の書庫に
ZIP形式で圧縮
----
次
----
CHAPTER::Close All Tabs-distribute
ALIGN::center
配布する
----
大きく分けて
二つの方法
----
・Mozilla Add-ons
で配布する
・自分で配布する
----
Mozilla Add-ons
[[https://addons.mozilla.org/]]
拡張機能のポータルサイト
----
1. アカウントを作成する
2. 拡張機能をアップロードする
3. [[EM:拡張機能がレビューされる]]
4. 承認されたら一般ユーザ向けに
公開される
----
自分で配布
する場合
----
XPIパッケージのMIME Type
[[EM:application/x-xpinstall]]
ダウンロードさせたい場合
[[EM:application/octet-stream]]
ALIGN::center
----
注意点
----
他の拡張機能と
バッティングしないか?
(要素のIDが重複していないか)
----
次
----
CHAPTER::Open Bookmark in Tab
FOOTER::
拡張機能のタイプ
・新機能を加える物
・既存の機能の
挙動を変える物
----
既存の機能の
挙動を変える
----
CHAPTER::Open Bookmark in Tab-overview
FOOTER::拡張機能を実際に作ってみる - Open Bookmark in Tab
ALIGN::center
[[EM:Open Bookmark in Tab]]
ブックマークを常に
新しいタブで
開くようにしてみる
----
目標(要求仕様)
・ブックマークを左クリックしたら
新しいタブで、
中クリックしたら現在のタブで
開くようにする。
・現在のタブが空(about:blank)
の場合、新しいタブを開かずに
現在のタブで開く。
(無駄なタブを開かない)
----
作業手順
1. IDを決める
2. どこをいじればいいか調べる
3. フォルダとファイルを用意する
4. XULで構造を定義する
5. JavaScriptで挙動を定義する
6. パッケージングする
7. 配布
----
CHAPTER::Open Bookmark in Tab-ID
ALIGN::center
IDを決める
----
[[EM:UUID(GUID)]]:完全なID
{E0EACCD1-98F3-4936-A229-41C667E820B8}
[[EM:名前@ドメイン]]:簡易的なID
openbookmarkintab@piro.sakura.ne.jp
----
CHAPTER::Open Bookmark in Tab-Inspect
ALIGN::center
どこをいじれば
いいか調べる
----
方法は
2つ
----
・動いているFirefox上で
改造箇所を探す
・ソースコード上で
改造箇所を探す
----
DOMインスペクタ
----
動作中の
Firefoxの
内部コードを
覗き見る
----
ソースコード全文検索
(LXR)
[[lxr.mozilla.org/mozilla/]]
----
ビルド前の
ソースコードを
覗き見る
----
もう1つ
裏技
----
ビルド済みの
Firefoxを
展開してみる
----
C:\Program Files\Mozilla Firefox\chrome\
にある
・browser.jar
・toolkit.jar
あたりをZIP書庫として展開してみる
----
ビルド前の
ソースとは
ちょっと違う
----
[[EM:ステップ1]]
DOMインスペクタで
コマンドを分析
----
実演
----
[[PRE:BookmarksMenu.loadBookmark()]]
が呼ばれていることが判明
----
[[EM:ステップ2]]
[[PRE:BookmarksMenu.loadBookmark()]]
の定義を調べる
----
ソースコードの
全文検索
----
[[http://lxr.mozilla.org/mozilla1.8/|lxr1.htm]]
Firefox 2のソースコード
----
「BookmarksMenu」
を[[Text Search|lxr2.htm]]
----
bookmarksMenu.js
というファイルで定義
されていることが判明
----
「loadBookmark」
で[[ページ内|lxr3.htm]]を検索
----
見つかったメソッド「loadBookmark」の定義
[[PRE:
loadBookmark: function (aEvent, aTarget, aDS)
{
if (aTarget.getAttribute("class") == "openintabs-menuitem")
aTarget = aTarget.parentNode.parentNode;
// Check for invalid bookmarks (most likely a static menu item like "Manage Bookmarks")
if (!this.isBTBookmark(aTarget.id))
return;
var rSource = RDF.GetResource(aTarget.id);
var selection = BookmarksUtils.getSelectionFromResource(rSource);
var browserTarget = whereToOpenLink(aEvent);
BookmarksCommand.openBookmark(selection, browserTarget, aDS);
aEvent.stopPropagation();
},
]]
----
[[PRE:
BookmarksCommand.openBookmark()
]]
が呼ばれている
----
「BookmarksCommand」
を[[Text Search|lxr4.htm]]
----
bookmarks.js
で定義されている
----
「openBookmark」
で[[ページ内|lxr5.htm]]を検索
----
見つかったメソッド「openBookmark」の定義
[[PRE:
openBookmark: function (aSelection, aTargetBrowser, aDS)
{
if (!aTargetBrowser)
return;
// in this case, we can just use |aSelection.length| as "Open in Tabs"
// is only available when you are only selecting multiple bookmarks
// if you selected a folder of bookmarks, we check the number of tabs in
// openGroupBookmark()
if (aTargetBrowser == "tab" && !this._confirmOpenTabs(aSelection.length))
return;
for (var i=0; i
]]
JavaScriptを読み込むためだけのシンプルなもの
----
CHAPTER::Open Bookmark in Tab-JavaScript
ALIGN::center
JavaScript
でメソッドを
再定義する
----
openbookmarkintab.js
[[PRE:
window.addEventListener('load', function() {
var originalOpenBookmark = BookmarksCommand.openBookmark;
BookmarksCommand.openBookmark = function(aSelection, aTargetBrowser, aDS) {
if (aSelection.length == 1) {
if (aTargetBrowser == 'current' &&
gBrowser.currentURI.spec != 'about:blank')
aTargetBrowser = 'tab'; // = 'tabshifted';
else if (aTargetBrowser == 'tab' || aTargetBrowser == 'tabshifted')
aTargetBrowser = 'current';
}
return originalOpenBookmark.call(this,
aSelection, aTargetBrowser, aDS);
};
}, false);
]]
----
内容の
解説
----
[[PRE:
window.addEventListener('load', function() {
...
}, false);
]]
ブラウザウィンドウが開かれた直後に
内容を実行する
----
[[PRE:
var originalOpenBookmark =
BookmarksCommand.openBookmark;
]]
元のメソッドの関数オブジェクトを
変数に保持しておく
----
[[PRE:
BookmarksCommand.openBookmark =
function(aSelection, aTargetBrowser, aDS) {
]]
メソッドを再定義する
----
[[PRE:
if (aSelection.length == 1) {
...
}
]]
開くブックマークが一つだけの時だけ
特別な処理を行う
----
[[PRE:
if (aTargetBrowser == 'current' &&
gBrowser.currentURI.spec != 'about:blank')
aTargetBrowser = 'tab'; // = 'tabshifted';
]]
ブックマークを現在のタブに読み込むはずで、
且つ、現在のタブの内容が空でない場合、
代わりに新しいタブを開く
----
[[PRE:
else if (aTargetBrowser == 'tab' ||
aTargetBrowser == 'tabshifted')
aTargetBrowser = 'current';
}
]]
ブックマークを新しいタブに読み込むはず
だった場合、現在のタブに読み込む
----
[[PRE:
return originalOpenBookmark.call(this,
aSelection, aTargetBrowser, aDS);
};
]]
元のメソッドを実行して、
返り値を返す(←ここ重要)
----
他の拡張機能が
同じメソッドを
置き換えようとして
且つ
そのメソッドの
返り値が重要な場合
----
返り値を返さない
→その2つの拡張機能が
同時にインストール
された時にエラーが
起こる
----
原則として
返り値は常に
返した方が安全
----
参考
----
Function.call()の代わりに
Function.apply()を使う
[[PRE:
return originalOpenBookmark.apply(this,
[aSelection, aTargetBrowser, aDS]);
// return originalOpenBookmark.apply(this,
// arguments);
]]
メソッドの引数の数が不定だったり
引数に変更を加えなかったりする場合は
こちらの方が便利なことも
----
変数ではなくプロパティに
元のメソッドを保持する
[[PRE:
BookmarksCommand
.__openbookmarkintab__openBookmark =
BookmarksCommand.openBookmark;
...
return this.__openbookmarkintab__openBookmark(
aSelection, aTargetBrowser, aDS);
]]
元のメソッドを他の箇所からも呼び出したい
場合はこうしておくとよい
(メソッド名が重ならないよう気をつける)
----
次
----
CHAPTER::Open Bookmark in Tab-manifest
ALIGN::center
インストール
定義を書く
----
install.rdf
[[PRE:
]]
----
chrome.manifest
[[PRE:
content openbookmarkintab
chrome/content/openbookmarkintab/
overlay chrome://browser/content/browser.xul
chrome://openbookmarkintab/content/openbookmarkintab.xul
]]
----
ALIGN::center
XPIパッケージを
作成する
----
ALIGN::center
配布する
----
ALIGN::center
注意点
----
他の拡張機能と
バッティングしないか?
(返り値の問題や、
元のメソッドを保持
しているかどうか)
----
Firefoxのバージョンが
変わっても動作するか?
(メソッド名の変更、
引数の数や順番の変更、
そもそもの処理内容の変更)
----
メソッドの置き換えは
Firefoxのバージョン間の
互換性維持に気をつける
----
CHAPTER::締め
HEADER::
FOOTER::
以上
----
ご清聴
ありがとう
ございます
----
質疑
応答