はてなブックマークのタグをソートする Greasemonkey script

はてなブックマーク改造用Greasemonkey詰め合わせ

はてブグリモンその4 はてなホットタグ1.1
(番外編)はてブグリモンその5 はてなタグソート

なんてものを見つけたので、改造してみた。

ソートに使う項目は以下:

  1. 今表示してるページのタグ数
  2. タグの世代(tag-latestとかってやつ)
  3. タグのサイズ(規模)
  4. タグ名

元ネタを作った小野マトペ様に感謝。

場所は以下:
yahoo breafcase/HatenaTagSort2.user.js
右クリして View user script source でインストール。


ソースを以下にも書いとく。

// ==UserScript==
// @name          HatenaTagSort2
// @namespace     http://d.hatena.ne.jp/buzztaiki/
// @description   Sort ?B taglist by various order. If you custmoize order, modify `sortOrder' variable.
// @include       http://b.hatena.ne.jp/*
// ==/UserScript==

// Original source: http://www.onomatope.2-d.jp/program/firefox/HatenaTagSort.user.js

(function() {
    var sortOrder = [
        'compareCountTo',
        'compareAgeTo',
        'compareSizeTo',
        'compareTagNameTo'
    ];

    // ----------------------------------------------------------------

    function getElementsByClassName(parent, className, tagName) {
        tagName = tagName || '*';
        var elems = parent.getElementsByTagName(tagName);
        var targetElems = [];

        for (var i = 0; i < elems.length; i++) {
            var classNames = elems[i].className.split(/ +/);

            INNER:
            for (var j = 0; j < classNames.length; j++) {
                if (classNames[j] == className) {
                    targetElems.push(elems[i]);
                    break INNER;
                }
            }
        }

        return targetElems;
    }

    // ----------------------------------------------------------------

    // Cache for store method value.
    function Cache() {
        this.value = null;
    }

    Cache.prototype.set = function(value) {
        this.value = value;
        return this.value;
    };

    // ----------------------------------------------------------------

    // Tag.
    // Hold sort method and reference of tag element.
    function Tag(tagElem) {
        this.tagElem = tagElem;
        this.count = 0;
        this.caches = {};

        var cacheNames = [
            'aElem',
            'size',
            'tagName',
            'age'
        ];

        for (var i = 0; i < cacheNames.length; i++) {
            this.caches[cacheNames[i]] = new Cache();
        }
    }

    Tag.prototype.aElem = function() {
        var cache = this.caches.aElem;
        if (cache.value) {
            return cache.value;
        }

        return cache.set(this.tagElem.getElementsByTagName('a')[0]);
    };

    Tag.prototype.size = function() {
        var cache = this.caches.size;
        if (cache.value) {
            return cache.value;
        }

        var fontSize = this.aElem().style.fontSize;
        return cache.set(parseFloat(fontSize.replace(/pt$/, '')));
    };

    Tag.prototype.tagName = function() {
        var cache = this.caches.tagName;
        if (cache.value) {
            return cache.value;
        }

        return cache.set(this.aElem().firstChild.data);
    };

    Tag.prototype.age = function() {
        var cache = this.caches.age;
        if (cache.value) {
            return cache.value;
        }

        var targetNames = [
            'tag-latest',
            'tag-later',
            'tag-earlier',
            'tag-earliest'
        ];
        var className = this.aElem().className;
        for (var i = 0; i < targetNames.length; i++) {
            if (targetNames[i] == className) {
                return cache.set(i);
            }
        }

        return cache.set(99);
    };

    Tag.prototype.compareAgeTo = function(other) {
        return this.age() - other.age();
    };

    Tag.prototype.compareSizeTo = function(other) {
        return other.size() - this.size();
    };

    Tag.prototype.compareTagNameTo = function(other) {
        if (this.tagName() < other.tagName()) {
            return -1;
        }
        else if (this.tagName() > other.tagName()) {
            return 1;
        }
        else {
            return 0;
        }
    };

    Tag.prototype.compareCountTo = function(other) {
        return other.count - this.count;
    };

    Tag.compare = function(a, b) {
        for (var i = 0; i < sortOrder.length; i++) {
            var cmp = a[sortOrder[i]](b);
            if (cmp !== 0) {
                return cmp;
            }
        }

        return 0;
    };

    // ----------------------------------------------------------------

    function createTagCounts() {
        var tagCounts = {};

        var bookmarkElems = getElementsByClassName(document, 'bookmarklist', 'dl');
        for (var i = 0; i < bookmarkElems.length; i++) {
            var tagElems = getElementsByClassName(bookmarkElems[i], 'tag', 'span');
            for (var j = 0; j < tagElems.length; j++) {
                var tag = tagElems[j].getElementsByTagName('a')[0].firstChild.data;

                if (!tagCounts[tag]) {
                    tagCounts[tag] = 0;
                }

                tagCounts[tag] += 1;
            }
        }

        return tagCounts;
    }

    function createTags(tagCounts) {
        var taglistElem = document.getElementById('taglist');
        var tagElems = taglistElem.getElementsByTagName('li');

        var tags = [];
        for (var i = 0; i < tagElems.length; i++) {
            var tag = new Tag(tagElems[i]);
            tag.count = tagCounts[tag.tagName()] || 0;
            tags.push(tag);
        }
        return tags.sort(Tag.compare);
    }

    // ----------------------------------------------------------------

    var tags = createTags(createTagCounts());

    var spaceNode = document.createTextNode(' ');

    var taglistElem = document.getElementById('taglist');
    var newTaglistElem = taglistElem.cloneNode(false);
    newTaglistElem.appendChild(spaceNode.cloneNode(false));

    for (var i = 0; i < tags.length; i++) {
        var tagElem = tags[i].tagElem.cloneNode(true);
        if (tags[i].count > 0) {
            var countElem = document.createElement('span');
            countElem.setAttribute('style', 'font-size: 8pt;');
            countElem.appendChild(document.createTextNode(':' + tags[i].count));
            tagElem.appendChild(countElem);
        }
        newTaglistElem.appendChild(tagElem);
        newTaglistElem.appendChild(spaceNode.cloneNode(false));
    }

    taglistElem.parentNode.replaceChild(newTaglistElem, taglistElem);
})();