Text Link テキストリンクの紹介

Mozilla.Party.jp 5.0のXULコンテスト用に作成した、テキストリンクの資料です。

コンセプト

URIの文字列を簡単に読み込む。

概要

この拡張機能は、リンクになっていないURI文字列をダブルクリックしたときに、それをリンクのように読み込むというものです。

文字列を選択してURIをとして開くという拡張機能やBookmarkletはいくつかあります(拙作「コンテキストメニュー拡張」もそのひとつです)が、ダブルクリックするだけで開けるというものは見かけなかったので、思いつきで作ってみました。後で知ったことですが、Operaにも同様の機能があると聞きました。そのことから考えても、潜在的な需要はあるものと思います。

余談ですが、この拡張機能は、当初は拙作XULアプリの「コンテキストメニュー拡張」で一機能として実装していました。それをタブ関係の拡張機能を活用するために「タブブラウザ拡張」に移植し、さらに、タブブラウザ拡張のスリム化のため、また、この機能だけを使いたいという方のニーズに応えるために単一の拡張機能として分離して……といった紆余曲折を経て、現在に至っています。

実装のポイント

この機能を実現するにあたってのポイントは、ユーザーがアクションを起こした正確な場所を知ることと、URI形式の文字列だけを抽出することの2つです。この拡張機能では、「ユーザーがクリックした箇所のテキスト」を得て、「正規表現でURI文字列を抜き出し」、「URI文字列の部分がクリックされたかどうかを調べる」ことで、これらの課題をクリアしています。順を追って以下にご説明しましょう。

クリック位置の取得

ユーザーがページの中をクリックした時、Mozillaはその部分を「長さ0の選択範囲」にします。

Mozilla内部では、windowオブジェクトのgetSelection()メソッドを使うことで、選択範囲をnsISelectionというインターフェースのオブジェクトとして取得できます。このnsISelectionはW3CのDOM Level2にある「Range」によく似ていて、ここから、選択範囲の開始位置や終了位置、選択範囲が含まれているノードなどの情報を得ることができます。

この拡張機能は、ユーザーがページの中をダブルクリックした時、そのイベントを捕捉して選択範囲を取得し、次の機能に処理を渡します。

クリック位置の周辺のテキストを取得する

通常のテキスト内で長さ0の選択範囲が存在する時、選択範囲の開始点と終了点は必ずテキストノードに含まれます。このテキストノードはnsISelectionのanchorNodeプロパティ(選択開始点が含まれているノードを示す)で取得できるので、さらにそのnodeValueプロパティを参照することで、「URI文字列が含まれているであろうテキスト」を得ることができます。

選択範囲の情報を元にURIを得る

次に行うのは、このテキストの中に含まれているURIの抜き出しです。この段階ではまだ、そのURIがクリックされたかどうかは考えません。

正規表現でのURI文字列の抜き出しは、掲示板などのCGIスクリプトなどでも使われるポピュラーな手法です。URI文字列を表す正規表現には、大崎 博基氏による「Perlメモ」の「http URL の正規表現」の項で紹介されているものを参考に \w+:(//)?[-_.!~*'()a-z0-9;/?:@&=+$,%#]+ を使っています。また、相対URLも含めた検索に対しては [-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+(\.|/)[-_.!~*'()a-z0-9;/?:@&=+$,%#]+ も併用しています。これらの正規表現は全てのURIにマッチするものではありませんが、全てのURIにマッチする正規表現だと普通のテキストまでがヒットしてしまうことと、通常Web上で見かけるURI文字列はある程度形式が限られている事を考え、このようにしています。

※2004.8.8現在の最新版では、後者の正規表現は「相対パスを解釈する」設定が有効な時にのみ使用し、通常は前者のみを使うようになっています。

URI文字列が含まれていたら、今度はそれをテキストの中でindexOf()メソッドで検索して、出現位置とURI文字列の長さから、テキスト中のどこからどこまでがそのURI文字列であるかを調べます。そして、それと選択範囲の開始点・終了点のオフセット値とを比較し、選択範囲がURI文字列のある範囲に含まれているかどうかを判別します。

これらのプロセスを経て、初めて「URI文字列がクリックされた」事が分かり、同時に、クリックされたURI文字列を取得することができるというわけです。

今後の課題、検討事項

今のバージョンでは、選択範囲の含まれているテキストノードだけが検索対象になるので、URI文字列の一部だけが強調されているといった場合などに「ユーザーの目に見えている」URI文字列を正しく取得できません。この問題に対する対処を考える必要があるというのがまず一つめの課題です

もう一つの問題は、正規表現によるURIの検索の精度が低いことです。これは相対パスを検索対象に含める(「URIの補完を行う」の機能の一つ)(※2004.8.8現在、この設定は「相対パスを解釈する」と「スキーマを補完する」の二つに分割されています)と顕在化します。

リファラの扱いも課題です。私はこの拡張機能を、ページ作者がハイパーリンク化していないURI文字列をリンクのように扱う、という考え方で作りました。ですから、ジャンプ先のページには通常のリンクと同様、HTTP_REFERERを渡すようにしていました。HTTP_REFERERについてはRFC2616の14.36で「ジャンプ先URIがそのページに含まれていない場合は送信してはならない」と定められているのみなので、この動作自体については問題がないと考えられます。

しかし、この拡張機能を「URI文字列を選択して、コピーし、ロケーションバーに貼り付け、そのURIを読み込む」という一連の操作を自動化するだけのものであると考えた場合、HTTP_REFERERはジャンプ先に知らせないというのが「ユーザーに期待される動作」です。ページ作者がリンクせずにわざわざURI文字列の形で書いているのは、「ジャンプ先に知られたくない」という意思の表れである、だからHTTP_REFERERは渡すべきではない、という意見もあります。

現在の所、リファラについてはデフォルトでは送信、設定でカットすることもできるようにしています。折衷案としてはこれが妥当なところだと思うのですが、まだまだ理解を頂けていないこともあるようで、頭の痛いところです。