はてブコメントの並び順を変えるグリモン書いた

はじめて Greasemonkey 書きましたよ。おかしなところがあったら教えてください。

さいしょ はてなブックマークのコメントを昇順に並べ替えるGreasemonkey を使ってたんですけど,いろいろ不満があったので書き換えてみました。原型はとどめてない。

light じゃない版あったのカー→http://userscripts.org/scripts/show/37784。じゃあこれいらないや。

  • ページを読み込んだ段階では,ソートボタンを付与するだけで何もしない
    • 問答無用でソートするとコメント数が多いページで待ちが多くなるので
  • 何種類かのボタンを指定できる
  • ソート順を指定する関数を指定できる
  • ソート中は「ソート中」って出る

まぁ「指定できる」ってのは,コード(setup() 部分)書き換えてくださいねっていうレベルなんですけれど。

ほんとは http://white.s151.xrea.com/wiki/index.php?script/SBMCommentsViewer とか使えばいいんでしょうけど,結構ブクマの entry ページとかよく見るんですよ。

// ==UserScript==
// @name           Sort HB Comment 2
// @namespace      http://d.hatena.ne.jp/dayflower/
// @description    Sort Hatena Bookmark Entry Page
// @include        http://b.hatena.ne.jp/entry/*
// @include        http://b.hatena.ne.jp/entry/?mode=more&url=*
// ==/UserScript==

(function () {

setup([
    {   // 逆順 (コメント優先)
        label: '\u25bd\u9006\u9806',
        criteria: function (a, b) {
            // first criteria: comment
            var ac = a.getAttribute('class') || '';
            var bc = b.getAttribute('class') || '';

            if (bc.match(/nocomment/)) {
                if (! ac.match(/nocomment/))
                    return -1;
            }
            else {
                if (ac.match(/nocomment/))
                    return 1;
            }

            // second criteria: original order (reverse)
            return b.xHatebuOrder - a.xHatebuOrder;
        }
    },
    {   // 元の順序
        label: '\u25bd\u6b63\u9806',
        criteria: function (a, b) {
            return a.xHatebuOrder - b.xHatebuOrder;
        }
    }
]);

var items;      // GLOBAL

function setup(confs) {
    var marks = document.getElementById('bookmarked_user');
    if (! marks)
        return;
    if (marks.childNodes[1].textContent
                     // 非表示に設定
             .match(/\u975e\u8868\u793a\u306b\u8a2d\u5b9a/))
        return;

    var res = document.evaluate(
        '//h2[@class="comment bookmark-list"]/span/span[@class="count"]',
        document.body,  null, 7, null
    );
    if (res.snapshotLength <= 0)
        return;
    var area = res.snapshotItem(0);
    for (var i = 0, n = confs.length; i < n; i ++)
        add_button(area, confs[i]);
}

function init_items() {
    var marks = document.getElementById('bookmarked_user');
    var items = [];

    if (1) {
        var t = marks.getElementsByTagName('li');

        for (var i = 0, n = t.length; i < n; i ++) {
            items[i] = t[i];
            items[i].xHatebuOrder = i;
        }
    }
    else {
        var res = document.evaluate('li', marks,  null, 7, null);

        for (var i = 0, n = res.snapshotLength; i < n; i ++) {
            items[i] = res.snapshotItem(i);
            items[i].xHatebuOrder = i;
        }
    }

    return items;
}

function do_sort_comments(criteria) {
    if (items == null)
        items = init_items();

    items.sort(criteria);

    var marks = document.getElementById('bookmarked_user');

    var newlist = document.createElement('ul');
    newlist.setAttribute('class', marks.getAttribute('class'));

    for (var i = 0, n = items.length; i < n; i ++)
        newlist.appendChild(items[i]);

    newlist.setAttribute('id', marks.getAttribute('id'));
    marks.parentNode.replaceChild(newlist, marks);
}

function add_button(area, conf) {
    var link = document.createElement('a');
    link.style.cursor = 'pointer';
    link.style.color  = '#fff';

    link.innerHTML = conf.label || '\u25bd';

    if (conf.title)
        link.title = conf.title;

    link.addEventListener('click', function (e) {
        var me = e.target;

        //              TEXTNODE
        var backup = me.firstChild.nodeValue;
        //                         ソート中…
        me.firstChild.nodeValue = '\u30bd\u30fc\u30c8\u4e2d\u2026';

        window.setTimeout(
            function () {
                do_sort_comments(conf.criteria);
                me.firstChild.nodeValue = backup;
                //me.parentNode.style.visibility = 'hidden';
            },
            0
        );

        e.preventDefault();
    }, true);

    var button = document.createElement('span');
    button.appendChild(document.createTextNode('\u3000['));
    button.appendChild(link);
    button.appendChild(document.createTextNode(']'));

    area.appendChild(button);
}

はじめて Greasemonkey 書いて感じたこと。

  • デバッグがめんどくさい
    • エラー時に firebug console に出力される内容がちょっと変だったり。環境依存?
  • でも DOM 操作とか非常に勉強になる
  • Firefox でしか動かない JavaScript を書くくせがつきそう
  • 自作スクリプトのインストールがめんどくさい
    • ドラッグドロップで登録できないんですけど…… Linux だから?
  • HTMLCollection の sort() ができなかったんで,Array にコピーしてます
    • Array.prototype.sort 使ってみたけどうまくいかなかったです