読者です 読者をやめる 読者になる 読者になる

AutoPagerize Hacks: Object.prototype.watch

AutoPagerize

Object.prototype.watch.call(window, "Autopagerize" ってやればGreasemonkeyでもwatch使えるな

http://twitter.com/flagmeister/statuses/877517059

を参考に、AutoPagerizeにインクリメントモードとURLフィルターを追加するプラグインを書いてみた - 0xFFを改良してみました。

インストール
(AutoPagerize本体より先に実行される必要があります。インストール後、ユーザースクリプトの管理でAutoPagerizeより上にドラッグしてください)
404 · GitHub

watchで window.AutoPagerize を捕まえて、さらに window.AutoPagerize.addDocumentFilter を捕まえています。

Object.prototype.watch.call(window,'AutoPagerize',function(key, a, AutoPagerize){
  Object.prototype.watch.call(AutoPagerize,'addDocumentFilter',function(key, a, addDocumentFilter){
    try {
      var AutoPager = eval('AutoPager', addDocumentFilter);
      var getElementsByXPath = eval('getElementsByXPath', addDocumentFilter);
      var SITEINFO = eval('SITEINFO', addDocumentFilter);
      var _initHelp = AutoPager.prototype.initHelp;
      AutoPager.prototype.initHelp = function(){
        _initHelp();
        var ap = this;
        if (window.AutoPagerize) AutoPagerizeFilter(AutoPager, ap, autopagerize_siteinfo,getElementsByXPath);
        if (window.Minibuffer) MinibufferHacks(AutoPager,ap);
      }
      autopagerize_siteinfo.forEach(function(s){
        SITEINFO.push(s);
      });
      AutoPagerizeHacks(getElementsByXPath,addDocumentFilter);
    } catch (e) {
      log(e);
      return addDocumentFilter;
    }
    Object.prototype.unwatch.call(AutoPagerize,'addDocumentFilter');
    return addDocumentFilter;
  });
  Object.prototype.unwatch.call(window,'AutoPagerize');
  return AutoPagerize;
});

AutoPagerize(0.0.31)側では、↓のようにwindow.AutoPagerize.addDocumentFilterが定義された後にlaunchAutoPagerが呼ばれます。以前のsetTimeout方式では一度実行されてしまったlaunchAutoPagerを強引に解除して実行し直していましたが、予めSITEINFOを追加しておいたり、AutoPager.prototype.*を弄るといったことが可能になりました(もちろん、現状の実装に依存するので将来的にはうまく動かなくなるかもしれません)。ただし、その分pluginは本体より先に実行される必要があります。インストール後は

if (typeof(window.AutoPagerize) == 'undefined') {
    window.AutoPagerize = {}
    window.AutoPagerize.addFilter = function(f) {
        AutoPager.filters.push(f)
    }
    window.AutoPagerize.addDocumentFilter = function(f) {
        AutoPager.documentFilters.push(f)
    }
}

GM_registerMenuCommand('AutoPagerize - clear cache', clearCache)
var ap = null
launchAutoPager(SITEINFO)

また、これを見ればわかりますが、documentFiltersを捕まえた時点ではapは必ずundefined*1です。apを取得するために、AutoPager.prototype.initHelpをオーバーライドしています。


watchはほぼ初めて使ってみたのですが、実行タイミングが厳密すぎて、ゆるいsetTimeoutに慣れてしまった今では使い難さを感じました。。まあ、watchのほうが扱いやすいというのが一般的だと思います。
特に考えなしにAutoPagerizeのforkに追加してみたけど、ここでよかったのか微妙だったかも。まあ、とりあえずはこのままで。

*1:nullではなく、undefinedなのは少しわかり難いが