素人がプログラミングを勉強していたブログ

プログラミング、セキュリティ、英語、Webなどのブログ since 2008

連絡先: twitter: @javascripter にどうぞ。

はてブにダイアリーのリンク付けるグリモンの添削

はてブユーザのストーキングを加速させるgreasemonkey(はてブしてるひとのダイアリーへのリンクを付加する) - Cherenkovの暗中模索にっきを勝手に添削する。

まず、気をつけたほうがいいもの。

// ==UserScript==
// @name           hateb_link_user_diary
// @namespace      http://d.hatena.ne.jp/Cherenkov/
// @include        http://b.hatena.ne.jp/entry/*
// ==/UserScript==

(function(){ // 最近のグリモンは無名関数で囲う必要がない(Operaのuser.jsとかは必要)
    var h = document.evaluate('//a[@class="hatena-id-icon"]', document, null, 7, null);

    for(i=0;i<h.snapshotLength;i++){ // iがグローバルになってる
        var diary = document.createElement('a');
        diary.href = h.snapshotItem(i).href.replace(/b.hatena.ne.jp/,'d.hatena.ne.jp'); //正規表現をエスケープしてない
        var img = document.createElement('img');
        img.src = 'http://d.hatena.ne.jp/images/de_favicon.ico';
        diary.appendChild(img);
        
        h.snapshotItem(i).parentNode.insertBefore(diary,h.snapshotItem(i).parentNode.childNodes[3]); // snapshotItemを何度も呼んでる
    }
})();

このへんを踏まえて修正する。空白とかは勝手に入れた。

// ==UserScript==
// @name           hateb_link_user_diary
// @namespace      http://d.hatena.ne.jp/Cherenkov/
// @include        http://b.hatena.ne.jp/entry/*
// ==/UserScript==

var h = document.evaluate('//a[@class="hatena-id-icon"]', document, null, 7, null);
for (var i = 0;i < h.snapshotLength;i++) {
  var icon = h.snapshotItem(i);
  var diary = document.createElement('a');
  diary.href = icon.href.replace("b.hatena.ne.jp", "d.hatena.ne.jp");
  var img = document.createElement('img');
  img.src = 'http://d.hatena.ne.jp/images/de_favicon.ico';
  diary.appendChild(img);

  icon.parentNode.insertBefore(diary, icon.parentNode.childNodes[3]);
}

/b.hatena.ne.jp/だとbxhatenaxnexjpとかにもマッチしてしまうので、/b\.hatena\.ne\.jp/か、必要がなければ文字列にするべき。

で、細かいこと。
まず、document.evaluateの引数の7は、対応する定数がある(Introduction to using XPath in JavaScript - MDN)ので、それを使うといいかもしれない。7の代わりにXPathResult.ORDERED_NODE_SNAPSHOT_TYPE。
XPathとclass属性は相性が悪い(特定のclass属性を持った任意の要素にマッチするXPath | 3.14)ので、ターゲットがFirefox3ならdocument.getElementsByClassNameを使うのも手。

ループ内でdocument.createElementとappendChildを使って毎回似た構造のものを作るのは速度的に不利なので、ループの外側でテンプレートを作って、cloneNodeするといい。

あと、childNodes[3]だと、サイト構造の変化に弱いので、iconの位置に対する相対的な指定にするといい。

これを踏まえて書き直すと、下のような感じになる。

// ==UserScript==
// @name           hateb_link_user_diary
// @namespace      http://d.hatena.ne.jp/Cherenkov/
// @include        http://b.hatena.ne.jp/entry/*
// ==/UserScript==

var icons = document.getElementsByClassName('hatena-id-icon'),
    link = document.createElement('a'),
    img = document.createElement('img');
img.src = 'http://d.hatena.ne.jp/images/de_favicon.ico';
link.appendChild(img);

for (var i = 0, len = icons.length;i < len;++i) {
  var icon = icons[i];
  if (!/a/i.test(icon.nodeName)) continue; // skip <img class="hatena-id-icon">
  var elem = link.cloneNode(true);
  elem.href = icon.href.replace('b', 'd');
  icon.parentNode.insertBefore(elem, icon.nextSibling);
}

以上。おせっかいだったらごめんなさい。