htsign's blog

ノンジャンルで書くつもりだけど技術系が多いんじゃないかと思います

httpやttpやtpなリンクのないURLにリンクを付けるありきたりなスクリプトを回りくどいコードで書いた

主に自分で使う用に。
よく出回ってるようなコードは "簡素だけどDOM標準は無視" というのが多かった(大体innerHTMLreplaceしてる)ので、ならばと自分で書きました。

(function(){
   // Rangeが使えなければ意味が無いので、ここで一旦判定をしています。
  if (!document.createRange)
    return window.alert("このスクリプトを実行するために必要なAPIが使用できません。");

  var range = document.createRange();

  (function(currentNode){
    var childs = currentNode.childNodes;
    var pattern= /h?t?tp(s?:\/\/(?:[\w-]+|[^ -~。-゚]+)\.[a-zA-Z]{2,4}[^\s ]*)/g;
    var regRes = [];

    for (var i = 0, l = childs.length; i < l; i++) { // 子ノードがいる場合に再帰
      var self = childs[i];
      if (self.childNodes && self.childNodes.length) {
        arguments.callee(self);
      }

      if (self.nodeType !== 3) continue; // テキストノードでなければ次へ

      while ((regRes = pattern.exec(self.textContent)) !== null) { // マッチがなくなるまでループ
        var a = document.createElement("a");
        a.href = "http" + regRes[1];
        range.setStart(self, regRes.index);
        range.setEnd(self, pattern.lastIndex);
        range.surroundContents(a);
      }
    }
  })(document.body);

  range.detach();
})();
ブックマークレット
javascript:(function(d){if(!d.createRange)return%20window.alert("このスクリプトを実行するために必要なAPIが使用できません。");var%20R=d.createRange();(function(n){var%20c=n.childNodes,p=/h?t?tp(s?:\/\/(?:[\w-]+|[^ -~。-゚]+)\.[a-zA-Z]{2,4}[^\s ]*)/g,r,i=0,l=c.length;for(;i<l;i++){var%20s=c[i];if(s.childNodes&&s.childNodes.length){arguments.callee(s)}if(s.nodeType!==3)continue;while((r=p.exec(s.textContent))!==null){var%20a=d.createElement("a");a.href="http"+r[1];R.setStart(s,r.index);R.setEnd(s,p.lastIndex);R.surroundContents(a)}}})(d.body);R.detach()})(document)

DOMでやってるので割とめんどくさい処理をしていると思います。
素直に innerHTML でやった方がコードも短いし処理も速いと思います。*1

しかも、テキストのURLがあったら問答無用でA要素で囲むので、
既にそのテキストにリンクがついていようがお構いなしです。HTMLの仕様上あまりよろしくありません。
もしかしたらブラウザによってはこのタイミングで例外を吐くかもしれません。
私の方でテストした限りでは動作上の問題は無いようでした。

いろいろ問題はありそうですが、でもいいんです。私はこういうのが好きなんです。

※テストしていたら同じタグ内に2つ以上のURLがあった場合、2つ目以降のURLに対してリンクがつかないバグが確認されました。
ただでさえ需要のないスクリプトがさらに需要のないものになっていますので使いたくならないのが普通だと思います。
気になってはいますし、バグのもとになっている場所も分かっていますが、バグが発生する原因が分からず停滞しています。
そのうち直したいとは思っています。


ちなみに、私のはてダで上のスクリプトを走らせるとプロフィールに書いてあるNYSL本家へのリンクが活性化すると思います。

*1:比較はしていませんが参考までに。Chromeでこのブックマークレットを music.google.com で動かすと、処理完了までに 10ms かかりました。それなりに複雑なページでも実用的な速度で終わるようです。