ユーザースクリプトと製作者スクリプト2008年08月02日 02時25分

あと、動作の細かな話ですが、オリジナルのAutoPagerizeとかぶってしまう(二重に読み込まれてしまう)ため、あえてa要素のrel属性(rel=”next”)を外して対処しています。

そろそろAutoPagerizeを標準的に導入していったらどうか - Liner Note

同じ機能を提供するユーザースクリプト (Greasemonkey スクリプト、Web ページに変更を加えるブラウザの拡張機能など) と製作者スクリプトがあった場合、その競合をどう解決するかということについて。最初は単にユーザースクリプト (ここでは特に AutoPagerize) を製作者スクリプトから無効化できるようにすればいいのかなと思いましたが、「3:14 - UserAgentの使い方について」を読んで考えを改めました。

ユーザースクリプトはブラウザの機能を補うものであり、ブラウザがもともと持っている機能と同一視できます。ある機能を (一般の Web ページを対象とした) ユーザースクリプトで実現するということは、それをブラウザの機能として、すなわち統一された操作感の下で提供するということです。同じ機能は同じ操作で実現できることを第一とするなら、ユーザースクリプトと製作者スクリプトとではユーザースクリプトのほうを優先させるべきです。

ではそのためにはユーザースクリプト、製作者スクリプトをどのように書けばいいのでしょうか。とりあえず考えてみたのが以下です。(本当に考えただけです。動かしてもいません。) 本題とは関係ありませんが、AutoPagerize のソースコードには文末にセミコロンがつけられていないんですね。

--- autopagerize.original.user.js	2008-08-01 17:16:41.531250000 +0900
+++ autopagerize.user.js	2008-08-02 01:09:41.500000000 +0900
@@ -28,6 +28,7 @@ var CACHE_EXPIRE = 24 * 60 * 60 * 1000
 var BASE_REMAIN_HEIGHT = 400
 var FORCE_TARGET_WINDOW = true
 var USE_COUNTER = true
+var FORCE_AUTO_PAGER = true
 var SITEINFO_IMPORT_URLS = [
     'http://wedata.net/databases/AutoPagerize/items.json',
 ]
@@ -575,7 +576,11 @@ var launchAutoPager = function(list) {
                 }
             }
             else {
-                ap = new AutoPager(list[i])
+                var event = document.createEvent('Event')
+                event.initEvent('AutoPagerizeReady', true, !FORCE_AUTO_PAGER)
+                if (document.dispatchEvent(event) || FORCE_AUTO_PAGER) {
+                    ap = new AutoPager(list[i])
+                }
                 return
             }
         }
// 製作者スクリプト

if (document.addEventListener) {
  document.addEventListener("AutoPagerizeReady", function (event) {
    if (event.cancelable) {
      // イベントがキャンセル可能 (ユーザースクリプト中の
      // FORCE_AUTO_PAGER の値が偽) ならキャンセルする。
      // このとき、製作者スクリプトの MyAutoPager が使われる。
      event.preventDefault();
    } else {
      // イベントがキャンセル可能でないなら
      // MyAutoPager を無効化して AutoPagerize を使う。
      disableMyAutoPager();
    }
  }, false);
  // AutoPagerize を使っていない環境ではそもそも
  // AutoPagerizeReady イベントが発生しないので
  // MyAutoPager がそのまま使われる。
}

initMyAutoPager();

このようにすれば、機能が衝突したときに、ユーザースクリプトを使うか製作者スクリプトを使うかをユーザー側で決定できます。常にユーザースクリプトを優先したいが、製作者スクリプトに無効化機能が公開されていない場合は、そのサイトの製作者スクリプトを無効化するユーザースクリプトを作る必要があるかもしれません (そのようなスクリプトを作るのが難しいことも多いでしょうが)。イベントを使うというアイデアは「Greasemonkeyスクリプトとウインドウ間で安全に通信する - ロックスターになりたい」からいただきました。

ある機能に関するスクリプトにも CSS のように、重要指定付きユーザースクリプト、製作者スクリプト、通常のユーザースクリプトと排他的な優先順位を設定する仕組みが整っていればいいんですけどね。排他的というより多層的といったほうがいいような気がしてきました。