リンクを左ボタン長押しによって新規タブに開きたい

かざぐるマウスというソフトでできる(左ボタン長押しにCtrl+Shift+クリックを割り当て)んだけど、僕の環境だとFirefoxだけうまく作用しない(効くリンクと効かないリンクがある)ので自分で作ることにした。

最初はGreasemonkeyスクリプトとして作っていたんだけど、Greasemonkeyでは新規タブを前面に開くことができないみたい。試したのは以下の方法。

window.open
ポップアップブロックに阻まれる
GM_openInTab
背面にしか開けない(browser.tabs.loadInBackgroundの設定に依存)
createEvent, initEvent, dispatchEventでCtrl+Shift+クリックイベントを生成・発火
Firefoxではデフォルトアクション(リンク先に移動)が実行されない
リンクを左ボタン長押しによって新規タブに開きたい - babu_babu_babooのごみ箱を参考に、マウスのボタンを押してから離すまでの時間で長押しかどうかを決めるタイプのGreasemonkeyスクリプトを作った。 javascriptプロトコルのリンクを無視するようにした。
// ==UserScript==
// @name           openLinkByLongPress
// @namespace      http://rikuba.com/
// @include        *
// ==/UserScript==

const WAIT = 500;

(function (listener) {
  document.addEventListener('mousedown', listener, false);
  document.addEventListener('click', listener, false);
})({
  timer: null,

  getAncestorOrSelfAnchor: function () {
    var expr = document.createExpression('ancestor-or-self::*[@href and not(starts-with(@href, "javascript:"))]', null);
    var xr = null;

    return function (node) {
      xr = expr.evaluate(node, XPathResult.ANY_UNORDERED_NODE_TYPE, xr);
      return xr.singleNodeValue;
    };
  }(),

  handleEvent: function (e) {
    if (e.button === 0) {
      this['on' + e.type](e);
    }
  },

  onmousedown: function (e) {
    var anchor = this.getAncestorOrSelfAnchor(e.target);
    if (anchor) {
      this.timer = e.timeStamp;
    }
  },

  onclick: function (e) {
    var anchor = this.getAncestorOrSelfAnchor(e.target);
    if (anchor) {
      if (WAIT < e.timeStamp - this.timer) {
        e.view.open(anchor.href);
        e.preventDefault();
      }
    }
  }
});
以下のuserChrome.jsスクリプトはバグがある。
(function() {
  var tid;
  var opened;
  
  function isLink(node) {
    if ((node instanceof HTMLAnchorElement || node instanceof HTMLAreaElement)
        && node.hasAttribute('href'))
      return node;
    return false;
  }
  
  gBrowser.mPanelContainer.addEventListener('mousedown', function(e) {
    if (e.button !== 0) return;
    var node = isLink(e.target) || isLink(e.target.parentNode);
    if (!node) return;
    tid = setTimeout(function() {
      gBrowser.selectedTab = gBrowser.addTab(node.href);
      opened = true;
    }, 500);
  }, false);
  
  gBrowser.mPanelContainer.addEventListener('mousemove', function(e) {
    if (tid == null) return;
    clearTimeout(tid);
    tid = null;
  }, false);
  
  gBrowser.mPanelContainer.addEventListener('click', function(e) {
    if (tid == null) return;
    if (opened) {
      e.preventDefault();
      opened = false;
    } else {
      clearTimeout(tid);
    }
    tid = null;
  }, false);
})();