最も簡単な方法は、専用のFirefox拡張機能を作成することでした。
ステップ1.不要なXUL/アドオン関連のものをたくさんやりたくありませんでした。「ブートストラップ」(または再起動なし)拡張機能にはinstall.rdf
、アドオンを識別するためのbootstrap.js
ファイルと、ブートストラップインターフェイスを実装するためのファイルのみが必要です。
ブートストラップインターフェイスは非常に簡単に実装できます。
const path = '/PATH/TO/EXTERNAL/CODE.js';
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
var loaderSvc = Cc["@mozilla.org/moz/jssubscript-loader;1"];
.getService(Ci.mozIJSSubScriptLoader);
function install() {}
function uninstall() {}
function shutdown(data, reason) {}
function startup(data, reason) { loaderSvc.loadSubScript("file://"+path); }
install.rdf
を新しいzipファイルのトップレベルに配置して拡張子をコンパイルしbootstrap.js
、zipファイル拡張子の名前をに変更します.xpi
。
ステップ2.本番環境とテスト環境を再現できるようにするために、自動化タスク専用のプロファイルを使用してFirefoxを起動するのが最も簡単な方法であることがわかりました。
- Firefoxプロファイルマネージャーを起動します。
firefox -ProfileManager
- 新しいプロファイルを作成し、簡単に再利用できる場所
testing-profile
を指定して(私は私のものと呼びます)、プロファイルマネージャーを終了します。
- ユーザーのmozilla構成から新しいプロファイルを削除
profiles.ini
します(通常のブラウジングに干渉しないようにするため)。
- そのプロファイルでFirefoxを起動します。
firefox -profile /path/to/testing-profile
- (addons.mozilla.orgではなく)ファイルシステムから拡張機能をインストールします。
- プロファイルを準備するために必要な他のことを行います。(例:サードパーティの証明書を追加し、関連するドメインのポップアップウィンドウを許可する必要がありました。)
- 1つの
about:blank
タブを開いたままにして、Firefoxを終了します。
- プロファイルのスナップショット:
tar cvf testing-profile-snapshot.tar /path/to/testing-profile
その時点から、自動化を実行するたびにtesting-profile-snapshot.tar
、既存のtesting-profile
フォルダーを解凍しfirefox -profile /path/to/testing-profile about:blank
、「元の」プロファイルを使用するように実行します。
ステップ3.Firefoxを使用して起動すると、起動するたびtesting-profile
に外部コードが「含まれる」ようになります。/PATH/TO/EXTERNAL/CODE.js
注:外部JavaScriptコードがプロファイル内にキャッシュされるため(つまり、開発中に望ましくない)、外部コードへの変更が表示されないため、上記の手順2で/PATH/TO/EXTERNAL/
フォルダーを別の場所に移動する必要があることがわかりました。次回の起動時)。
外部コードには特権があり、MozillaプラットフォームAPIのいずれかを使用できます。ただし、タイミングの問題があります。外部コードが含まれている(したがって実行されている)瞬間は、ChromeウィンドウオブジェクトDOMWindow
がまだ存在しない(したがってオブジェクトが存在しない)瞬間です。
DOMWindow
したがって、有用なオブジェクトが見つかるまで待つ必要があります。
// useful services.
Cu.import("resource://gre/modules/Services.jsm");
var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
var wmSvc = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
var logSvc = Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
// "user" code entry point.
function user_code() {
// your code here!
// window, gBrowser, etc work as per MozRepl!
}
// get the gBrowser, first (about:blank) domWindow,
// and set up common globals.
var done_startup = 0;
var windowListener;
function do_startup(win) {
if (done_startup) return;
done_startup = 1;
wm.removeListener(windowListener);
var browserEnum = wm.getEnumerator("navigator:browser");
var browserWin = browserEnum.getNext();
var tabbrowser = browserWin.gBrowser;
var currentBrowser = tabbrowser.getBrowserAtIndex(0);
var domWindow = currentBrowser.contentWindow;
window = domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
gBrowser = window.gBrowser;
setTimeout = window.setTimeout;
setInterval = window.setInterval;
alert = function(message) {
Services.prompt.alert(null, "alert", message);
};
console = {
log: function(message) {
logSvc.logStringMessage(message);
}
};
// the first domWindow will finish loading a little later than gBrowser...
gBrowser.addEventListener('load', function() {
gBrowser.removeEventListener('load', arguments.callee, true);
user_code();
}, true);
}
// window listener implementation
windowListener = {
onWindowTitleChange: function(aWindow, aTitle) {},
onCloseWindow: function(aWindow) {},
onOpenWindow: function(aWindow) {
var win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
win.addEventListener("load", function(aEvent) {
win.removeEventListener("load", arguments.callee, false);
if (aEvent.originalTarget.nodeName != "#document") return;
do_startup();
}
};
// CODE ENTRY POINT!
wm.addListener(windowListener);
ステップ4.そのコードはすべて「グローバル」スコープで実行されます。後で他のJavaScriptファイル(例:jQuery)をロードする必要がある場合は、 (グローバル!)スコープloadSubscript
内で明示的に呼び出しますnull
function some_user_code() {
loader.loadSubScript.call(null,"file:///PATH/TO/SOME/CODE.js");
loader.loadSubScript.call(null,"http://HOST/PATH/TO/jquery.js");
$ = jQuery = window.$;
}
これで、2番目のパラメーターとしてセレクター呼び出しに渡すことjQuery
で、anyで使用できます。DOMWindow
<DOMWindow>.document