キーボードだけでテキスト選択 〜疑似キャレットモード編〜

前回のリベンジ。

前のはイマイチ使い勝手が良くないので、キャレットモードのようにテキスト選択できるようにした。ブックマークレットは下に。

できること。

  • ブックマークレットを実行すると、ページ内の色々な要素に空間ナビゲーションでフォーカスできるようになる。
  • エンターを押すとその要素でキャレットモードに入る。
  • キャレットは要素を飛び越えても移動できる。(はずなんだけど、出来ない時もあるみたい。調査中解決した。↓修正しといた。)
  • もう一度同じブックマークレットを実行すると通常の状態に戻ってくれる。

だめなところ。

  • 疑似キャレットモードなので、選択だけじゃなくて挿入も出来てしまう。
  • キャレットモードになっている間だけ window.doNothing というグローバル関数を作っている。まあ用途的に問題ないと思う。
  • 現時点では iframe には対応していない。
  • 最初から contentEditable=true な要素は、このブックマークレットを2回実行すると contentEditable=false になってしまう。
  • キャレットモードになっておいてから、別のところにShift+矢印の空間ナビゲーションで移動しようとしても、単にテキスト選択になってしまうだけで出来ない。
    • 一旦キャレットモードから抜けるという手はもちろんある。
    • 僕は Shift+矢印ではないキーバインドで空間ナビゲーションしているので、この問題は回避できた。
    • Kuruma さんが1年半前にこんなことを書いてた↓。

ただしキーバインドについてはOperaFirefoxの実装を見習うべきだ。いや、見習うべきだった。Operaが現在空間ナビゲーションに割り当てているキーバインドはShift+方向キー。これはいつの日かページ内の文字列選択に利用されることになるだろう。そうなったときのユーザの混乱は容易に想像できる。Shift+Meta+方向キーが押しにくいのも事実だが、Shift+方向キーを選択すべきではなかったように思う。

Gran Paradiso 3 Alpha 3 (kuruman.org > Kuruman Memo)


空間ナビゲーションは Shift+矢印のままで放っておくのはもったいなすぎる。Ctrl+hjkl のように Ctrl ベースにすれば、入力欄にフォーカスがあるときでもそのまま空間ナビゲーションが始められる。この便利さを味わってほしい。

ブックマークレット

javascript:if(window.doNothing){
  document.body.contentEditable=false;
  [].forEach.call(
    document.all,
    function(e){
      e.contentEditable=false;
      e.removeEventListener('mouseover',window.doNothing,false);
    }
  );
  delete window.doNothing;
}else{
  window.doNothing=function(){;};
  document.body.contentEditable=true;
  [].forEach.call(
    document.all,
    function(e){
      e.contentEditable=true;
      e.addEventListener('mouseover',window.doNothing,false);
    }
  );
};void(0);

改行無しバージョン。

javascript:if(window.doNothing){document.body.contentEditable=false;[].forEach.call(document.all,function(e){e.contentEditable=false;e.removeEventListener('mouseover',window.doNothing,false);});delete window.doNothing;}else{window.doNothing=function(){;};document.body.contentEditable=true;[].forEach.call(document.all,function(e){e.contentEditable=true;e.addEventListener('mouseover',window.doNothing,false);});};void(0);