URLをリンク化するブックマークレット
http://q.hatena.ne.jp/1356135347#a1182565 にあった「URLをリンク化するjQueryプラグインとブックマークレット | TipsZone」に、とてもインスパイアされた。
とても良い感じなのだけれど、
- ちょっと重たい
- 人力検索 @はてなハイク でよく使われる http:// 無しのテキストも対象にしたい
- 複数回実行すると、アンカータグがどんどん入れ子になっていく
というわけで、自分用に書きなおしてみる。
jquery.url2link.js が重たい理由
jQuery ですっきりしたコードにはなっているのは良いのだけれど、find('*') を使ってるので、ページ中の全Nodeを指す jQuery オブジェクトの配列ができてしまう。
カレンダー(jQuery UI の datePicker)のように見た目は小さいけど、Element がいっぱいあるようなページだと、ちょっときつい。
フレームの中もたどるので、広告にももぐりこんでいくし。
DOM の firstChild と nextSibling でたどっていけば、不要な中間オブジェクトができないので軽いはず。
たどってゆくときに、Element と TextNode の区別がつくので、アンカータグの子要素を変換対象から外すことで、アンカータグが入れ子になっていくことも防げる。
http:// 無しの表現
ホストの表現で、[a-z]+\.hatena\.ne\.jp を追加。
とりあえず、q.hatena.ne.jp だけ変換できれば、当座の用は成す。
URL の表現でも、スペースなどの区切りを入れずに文章を続ける人もいるので、漢字は対象外とすることにした。
フレームの中に再帰的に潜っていく機能は無くても良いかな、という気がするけれど、とりあえず重さが気にならないので、残しておく。
というわけで、出来上がったのはこんな感じ。
(function(){ // URL 表現を拾うための正規表現 var RE_URL = /(?:h?t)?(tps?:\/\/[^/\s]+|[a-z]+\.hatena\.ne\.jp)((\/[A-Za-z0-9!-/:;=?@_~]*)?)/i; // プロトコルを補完するときに、どちらのタイプに引っかかったかを判定するための正規表現 var RE_TPS = /^tps?:\/\//i; // TextNode を url を指すアンカータグで置き換える function txt2anchor(txt, url) { var anchor = txt.ownerDocument.createElement("a"); anchor.href = url; anchor.target = "_blank"; anchor.innerHTML = txt.nodeValue; txt.parentNode.replaceChild(anchor, txt); } // TextNode 中に URL を指す表現があるかどうかを探し、アンカータグに置き換えてゆく function url2link(txt) { var result = RE_URL.exec(txt.nodeValue); if (result) { var middlebit = txt.splitText(result.index); var endbit = middlebit.splitText(result[0].length); var url; if (RE_TPS.test(result[1])) { url = 'ht' + result[1] + result[2]; } else { url = 'http://' + result[1] + result[2]; } txt2anchor(middlebit, url); return url2link(endbit); } return txt.nextSibling; } // DOM をたどって、URL を指す表現をアンカータグに置き換えてゆく function url2link_walk_element(ele) { var e = ele.firstChild; while (e) { if (e.nodeType == 3) { e = url2link(e); } else { if (e.nodeType == 1 && ! (e.tagName == "A" && e.href != "")) { // walk in <A name="xxx"> url2link_walk_element(e); } e = e.nextSibling; } } } // 自window と、含まれる frame, iframe に対して、再帰的に url2link_walk_element を実行する function url2link_walk_window(w) { url2link_walk_element(w.document.body); var ff = w.frames; for (var i = 0 ; i < ff.length ; ++i) { url2link_walk_window(ff[i]); } } url2link_walk_window(window); })();
Firefox でしか確認してないけど、DOM の Core API しか使ってないから、モダンブラウザなら何でも動くはず(多分)。
ついでに、Hatena::Let にもブックマークレットを置いてみた。
http://let.hatelabo.jp/a-kuma3/let/gYC-yv69yveYaQ
@2015-2-18
name 属性を指定した A タグの中をたどってなかったので、ちょっと修正。