Firefox 17 環境でのLDRize復活への手引き(unsafeWindow不使用バージョン)

Firefox 17になって恒例行事のごとくLDRizeが動かなくなって、しばらくどうしようもない感じでしたが、Firefox 16のときにちらっと目にしたエラーを頼りに修正かけたらあっさり動くようになったので、備忘録的に記事にしてみます。

前提のひとつとして、Firefox17からE4Xはデフォルトでオフになり(javascript.options.xml.content でオンには出来る)、将来的には削除されます。そのため、E4Xで書かれているヒアドキュメント部分はすべて文字列に置き換える必要があります。

で、残る問題はグリモン間のオブジェクトの共有。Minibufferオブジェクトが共有されてくれないとどうにもならない。
unsafeWindowを使っても良いなら、id:serian:20121122:p1([Firefox] firefox17とminibufferとldrizeとUserScriptLoaderとtombloo - うぇぶとらばぁす)で書かれているような改変でまったく問題ないのですが、unsafeWindowということはサイトの側からもMinibuffferをいじれる状態ということ。せめてgreasemonkey内くらいに影響範囲をおさえて自衛可能にしておきたいです。

ということで、基本的な方針は例によって例のごとく、Greasemonkey0.9.12以降でMinibufferとLDRizeが動かない理由とか - tyoro.exeと同じ。sharedObjectを処方すること。
Firefox17、greasemonkey1.5を前提としてます。

ちなみに、LDRizeAutoPagerizeまでsharedObjectにぶっこんでいるのは、こっちの手元ではLDRizeAutoPagerizeを利用するスクリプトを導入してあるから。必要なければ、最低限MinibufferのところだけあればLDRizeは復活できます。

greasemonkeyを直接いじる場合
diff貼る

diff --git a/components/greasemonkey.js b/components/greasemonkey.js
index 89d1575..6491421 100644
--- a/components/greasemonkey.js
+++ b/components/greasemonkey.js
@@ -490,11 +490,22 @@ service.prototype.injectScripts = function(
     scripts, url, wrappedContentWin
 ) {
   var chromeWin = getChromeWinForContentWin(wrappedContentWin);
+  var sharedObject = {
+    Minibuffer : null,
+    LDRize : null,
+    AutoPagerize : null,
+    __exposedProps__ : {
+      Minibuffer : "rw",
+      LDRize : "rw",
+      AutoPagerize : "rw"
+    }
+  };
   var firebugConsole = getFirebugConsole(wrappedContentWin, chromeWin);

   for (var i = 0, script = null; script = scripts[i]; i++) {
     var sandbox = createSandbox(
         script, wrappedContentWin, chromeWin, firebugConsole, url);
+    sandbox.sharedObject = sharedObject;
     runScriptInSandbox(script, sandbox);
   }
 };

diffを読めない人のための完成形はこんな感じ
injectScriptsのとこ

これが

service.prototype.injectScripts = function(
    scripts, url, wrappedContentWin
) {
  var chromeWin = getChromeWinForContentWin(wrappedContentWin);
  var firebugConsole = getFirebugConsole(wrappedContentWin, chromeWin);

  for (var i = 0, script = null; script = scripts[i]; i++) {
    var sandbox = createSandbox(
        script, wrappedContentWin, chromeWin, firebugConsole, url);
    runScriptInSandbox(script, sandbox);
  }
};

こうなる。

service.prototype.injectScripts = function(
    scripts, url, wrappedContentWin
) {
  var chromeWin = getChromeWinForContentWin(wrappedContentWin);
  var sharedObject = {
    Minibuffer : null,
    LDRize : null,
    AutoPagerize : null,
    __exposedProps__ : {
      Minibuffer : "rw",
      LDRize : "rw",
      AutoPagerize : "rw"
    }
  };
  var firebugConsole = getFirebugConsole(wrappedContentWin, chromeWin);

  for (var i = 0, script = null; script = scripts[i]; i++) {
    var sandbox = createSandbox(
        script, wrappedContentWin, chromeWin, firebugConsole, url);
    sandbox.sharedObject = sharedObject;
    runScriptInSandbox(script, sandbox);
  }
};

そんでtombloo

addAround使えばいいんだろうけど肝心のaddAroundをどう使えばいいのかよくわかんなかったのでパス。

vimperator

js <<EOM
autocommands.add(
  'VimperatorEnter', '.*',
  function () {
    let Cc = Components.classes['@greasemonkey.mozdev.org/greasemonkey-service;1'];
    if (Cc) {
      Cc = Cc.getService().wrappedJSObject;
      if (Cc.injectScripts.toSource().search('sharedObject') == -1) {
        Cc.injectScripts = liberator.eval(
          Cc.injectScripts.toSource()
            .replace(/(?=(?:var|let) (?:firebugConsole))/,  'var sharedObject = {\n    Minibuffer:null,\n    LDRize:null,\n    AutoPagerize:null,\n    __exposedProps__:{\n      Minibuffer:"rw",\n      LDRize:"rw",\n      AutoPagerize:"rw"}};\n  ')
            .replace(/(?=runScriptInSandbox\()/, 'sandbox.sharedObject = sharedObject;\n    ')
            .replace(/(?:}\)$)/, '  return sharedObject;\n})'),
        Cc.injectScripts);
      };
    };
  });
EOM