かなりすごいブログ

実際に読んで分かった、はてなJSのダメなコード

はてなブログJSについて

最近話題になってるはてなブログのjavascriptですが、このブログをMiddlemanで構築した時に「はてなブックマークブログパーツ」のjavascriptコードを読んでげんなりしたのを思い出したので、この際ついでにこっちも公にしておこうかと思って記事にします。はてなブログのJSではないという意味でタイトルは釣りです。

はてなブックマークブログパーツとは

はてなブックマークブログパーツとは、あなたがお持ちのブログにはてなブックマークの各種情報を貼り付けることができるブログパーツです。はてなが提供しているHTMLタグとjavascriptの読み込みコードを貼り付けることで設置することができます。

ブログパーツは複数種類あるのですが、今回はこのブログに貼ろうとした「ブックマークのコメントを表示」というパーツのコードを読んでみます。

ブログパーツの設置方法

さて、ブログパーツの設置方法解説ページには、以下の2ステップでブログパーツを貼り付けできると解説されています。

javascriptの読み込みとデフォルト設定の記述

<script type="text/javascript" charset="utf-8" src="http://b.hatena.ne.jp/js/bookmark_blogparts.js"></script>
<script type="text/javascript">
HBBlogParts.commentInsertSelector = [ 'div.hatena-bookmark-marker', 'div.article-body-inner', 'div.blogbody div.mainmore', 'div.blogbody div.main', 'div.entry-body-main'];
HBBlogParts.insertPosition = 'after';
HBBlogParts.permalinkSelector = [ 'div.hatena-bookmark-marker a', 'div h3 a', 'h2.title a', 'h2.entry-title a', '.posted a' ];
HBBlogParts.permalinkPathRegexp = /\/archives\/\d+\.html$/;
HBBlogParts.permalinkAttribute = 'href';
</script>

1行目ではhttp://b.hatena.ne.jp/js/bookmark_blogparts.jsを読み込み、2行目以降ではどうもオプションの設定を行っている様です。

ブックマークコメント一覧を表示したい位置にdivタグを設置

<div class="hatena-bookmark-marker" ><a style="display:none;" href="※"></a></div>

※)設置ブログ記事ページのURL

どうやら、hatena-bookmark-markerというclassが指定されたdivタグの中身がブックマークコメント一覧に置き換えられる様ですね。

オプション設定の変更

はてなブックマークコメント表示ブログパーツというページを見ると、オプション一覧の解説とオプションの書き換え方法が記載されています。これらのオプションを使って挙動や見た目をカスタマイズするらしいですね。

問題点

ここで結論から言ってしまうと、このjavascriptスクリプトのオプション指定方法には問題があり、オプションの指定が利きません。

解説します。

オプション用プロパティの宣言と上書き

このjavascriptコードは、オプション設定をグローバル変数HBBlogPartsというオブジェクトのプロパティを自分の好きな値で宣言することで指定できる様な形式にしています。

ここで、javascriptのコードを実際に読んでみましょう。

//alert('start');
if ( typeof HBBlogParts == 'undefined' ) {
    var HBBlogParts = {};
    HBBlogParts._alreadyShown = {};
    HBBlogParts.shownPermalinks = {};
    HBBlogParts.catchCount = 0;
}

一番最初のコードがこれです。この後このHBBlogPartsというオブジェクトのプロパティに、実際にはてなブックマークコメントを取得してブログのDOMに追加していく処理を持った関数が宣言されていきます。次に後半のコードを見ます。

HBBlogParts.Design = null;
HBBlogParts.useUserCSS = false;
HBBlogParts.cssName    = 'basic';
HBBlogParts.listPageCommentLimit = 3;
HBBlogParts.permalinkCommentLimit = 5;
var hatenaRegexp = new RegExp( '^https?://[^/]+.hatena.ne.jp/([^/]+)/' );

if ( hatenaRegexp.test( location.href ) ) {
    var userName = hatenaRegexp.exec(location.href)[1] || '';
    HBBlogParts.isHatenaService = true;
    if ( location.href.indexOf('g.hatena.ne.jp') > 0 ) {
        HBBlogParts.commentInsertSelector = 'div.section';
    } else {
        HBBlogParts.permalinkCommentInsertSelector = ['div.comment', 'div.section'];
        HBBlogParts.commentInsertSelector = 'div.section';
    }
    HBBlogParts.insertPosition = 'after';
    HBBlogParts.permalinkSelector = 'div.section h3 a';
    HBBlogParts.permalinkAttribute = 'href';
    HBBlogParts.permalinkPathRegexp = new RegExp( userName + '/\\d{8}');
    HBBlogParts.useCanonicalizedURI = false;
    HBBlogParts.listPageCommentLimit = 3;
    HBBlogParts.permalinkCommentLimit = 9999;
}

if ( typeof HBBlogPartsFromBookmarklet == 'undefined' ) {
    HBBlogParts.register();
} else {
    p('From Bookmark let');
}

HBBlogParts.registerという関数が呼ばれていますね。この関数はページのDOMロード完了を監視して、完了した時点でHBBlogParts.startという関数を呼びます。HBBlogParts.startは実際にブックマークコメントを取得してDOMを書き換えるメインルーチンです。

あれっちょっとまって…

これ、HBBlogParts.register関数を呼ぶ直前に、各オプションをデフォルト値で上書きしてませんか?

実際に、

HBBlogParts.listPageCommentLimit = 1;
HBBlogParts.Design = ['t','c','s']

とか指定しても、ブラウザのデベロッパーコンソールでHBBlogPartsのプロパティを見ると、やはりデフォルト値で上書きされてしまっています。

HBBlogParts.permalinkURIHBBlogParts.permalinkPathRegexpといったブログパーツの動作に不可欠なオプションはさすがに上書きされていないようですが、HBBlogParts.Designの様な、デフォルト値でもとりあえず動作するといったプロパティの多くがデフォルト値で上書きされています。

オプション設定とはなんだったのか…

処理の流れからして、どうしてもオプション指定をしたい場合、「HBBlogParts.registerが呼ばれた後」かつ「ページのDOM読み込みが完了して実際にHBBlogParts.start関数の処理が開始されてしまう前」といったピンポイントのタイミングで、非同期的にこれらHBBlogPartsオブジェクトのプロパティを書き換える必要があります。難易度高い…

こう改善してほしい

  • オプションを問答無用でデフォルト値で上書きするのやめて…
  • どうせ表示したい位置にdivタグを設置するのだから、グローバル変数のプロパティを書き換えるのでなく、data-*属性で各オプション設定を指定できるようにしてほしい
    • そうすればHBBlogPartsという変数でグローバル汚染しなくてもよいのでは。よくわかんないけど。
  • ついでにこっちもminifyとかgzip配信とかやってほしい

まとめ

はてなさんがやる気になってるっぽいですし、なんか直接報告しても反応ないという噂なので、便乗して公にしてブログパーツウィジェットのJSも改善してもらおうという記事でした。ブコメ一覧ウィジェット使いたいです。よろしくお願いします。

あと、私は普段Rubyばかり書いていてjavascriptにはあまり詳しくはないので、もし間違いがあれば訂正してお詫びします。という予防線を張っておきます。