※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

基本

ファイル構成

*.xpi
 ├ install.rdf
 ├ bootstrap.js   ←これが追加
 ├ chrome.manifest
 ├ content
 ├ locale 
 └ skin

install.rdf に追加

<em:bootstrap>true</em:bootstrap>

bootstrap.js の内容

function startup(data, reason) {
    // 拡張機能の起動時(Firefoxの起動、拡張機能の有効化など)に実行
}
function shutdown(data, reason) {
    // 拡張機能の終了時(Firefoxの終了、拡張機能の無効化など)に実行
}
function install(data, reason) {
    // 拡張機能のインストール時に一度だけ実行。この関数はオプションなので、無くても良い。
}
function uninstall(data, reason) {
    // 拡張機能のアンインストール時に一度だけ実行。この関数はオプションなので、無くても良い。
} 

制限

  • chrome.manifestでoverlayが使えない。
    • つまり既存の機能やUIを変更したい場合、xul overlayに頼らず全てjavascriptで処理しなければならない。
    • contentは使えるので独自のxulウィンドウ等を使う事は可能。
    • overrideなら使える。
  • chrome.manifestでstyleも使えない。
    • この辺もjavascriptで。
  • defaults/preferences/prefs.js によるデフォルト設定が出来ない。
    • 全部javascriptで。
  • 独自XPCOMコンポーネントを登録できない。使えない。


実際にどう書くか

例えばブラウザウィンドウにメニューを追加する場合、startup()には
  1. 既存のブラウザウィンドウをServices.wmで全て取得
  2. 取得した全ウィンドウにDOM操作でメニュー追加
  3. Services.wmかServices.wwで今後開かれるブラウザウィンドウを監視して、その都度メニューを追加
という処理を書く。
当然shutdown()には全ウィンドウを取得してメニューを削除する処理を書く。

ブラウザウィンドウの取得と監視

Cu.import("resource://gre/modules/Services.jsm");
 
// 拡張機能起動
function startup(data, reason) {
    WindowManager.setup(true);
}
// 拡張機能終了
function shutdown(data, reason) {
    WindowManager.setup(false);
}
// ウィンドウの監視と処理を行うためのオブジェクト
var WindowManager = {
    setup : function (isStart) {
        var prefix = (isStart) ? "" : "un";
        // 既存のウィンドウを取得
        var winEnum = Services.wm.getEnumerator("navigator:browser");
        while (winEnum.hasMoreElements()) {
            var win = winEnum.getNext();
            // 各ウインドウへの startup or shutdown の処理
            this[prefix + "initWindow"](win);
        }
        // 新規ウィンドウ監視の登録 or 解除
        Services.ww[prefix + "registerNotification"](this);
    },
 
    observe : function (subject, topic, data) {
        if (topic == "domwindowopened") {
            var win = subject.QueryInterface(Ci.nsIDOMWindow);
            var self = this;
            win.addEventListener("load", function load() {
                win.removeEventListener("load", load);
                if (win.document.documentElement.getAttribute("windowtype") == "navigator:browser") {
                    self.initWindow(win);
                }
            });
        }
    },
 
    initWindow   : function(window) {},  // 各ウィンドウへの startup 処理
    uninitWindow : function(window) {},  // 各ウィンドウへの shutdown 処理
}; 

スタイルの適用と除去

スタイルは nsIStyleSheetService に一度登録すると全ウィンドウに反映される。ウィンドウ毎に何かする必要はない。
var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
var uri = Services.io.newURI("chrome://sample/skin/browser.css", null, null);
function startup(data, reason) {
    // スタイル適用
    sss.loadAndRegisterSheet(uri, sss.AGENT_SHEET);
}
function shutdown(data, reason) {
    // スタイル除去
    if (sss.sheetRegistered(uri, sss.AGENT_SHEET)) {
        sss.unregisterSheet(uri, sss.AGENT_SHEET);
    }
} 

デフォルト値の設定

const PREFS = {
  someIntPref    : 1,
  someStringPref : "some text value",
};
function setDefaultPrefs() {
  var branch = Services.prefs.getDefaultBranch("extensions.myaddon.");
  for (let key in PREFS) {
    let val = PREFS[key];
    switch (typeof val) {
      case "boolean":
        branch.setBoolPref(key, val);
        break;
      case "number":
        branch.setIntPref(key, val);
        break;
      case "string":
        branch.setCharPref(key, val);
        break;
    }
  }
} 

ツールバーボタン(カスタマイズボタン)の追加

CustomizableUI.createWidget() を startup 内で一度使って widget を登録すれば、後は勝手にウィンドウ毎にボタンを作ってくれる。メニュー作成時のようなウィンドウ監視とかは必要ない。shutdown も同様。
Cu.import("resource:///modules/CustomizableUI.jsm");
function startup(data, reason) {
    // カスタマイズボタン追加
    CustomizableUI.createWidget({
        id: 'sample-button',
        type: 'button',
        tooltiptext: 'sample button',
        label: 'sample',
        onCommand: function(event) {
            let window = event.target.ownerDocument.defaultView;
            window.alert("sample alert");
        },
    });
}
function shutdown(data, reason) {
    // カスタマイズボタン削除
    CustomizableUI.destroyWidget('sample-button');
} 
type に view を設定してパネルがポップアップするボタンも作れるようなのだが、肝心のパネルの作成方法がどこにも書いていない……

このままだとアイコンが無いボタンが作成される。アイコンは上記の「スタイルの適用と除去」で button.css を適用/除去してやる。
button.css は
#sample-button {
    list-style-image: url(chrome://sample/skin/icon32.png);
}
#sample-button[cui-areatype="toolbar"] {
    list-style-image: url(chrome://sample/skin/icon16.png);
} 
あるいは、互換性を考慮するなら
#sample-button {
    list-style-image: url(chrome://sample/skin/icon16.png);
}
#sample-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #sample-button {
    list-style-image: url(chrome://sample/skin/icon32.png);
} 

注意

  • bootstrap.jsが読み込まれた時点では、まだchrome.manifest登録が行われていないのでchrome://パスが使えない。
  • jsm と同じように bootstrap.js も ascii で読み込まれるため、日本語を書くと文字化けしてしまう。