それ、うまいのか?

... 記憶の残滓

ページのリロードなしに、ウォッチリストの項目を削除する Bookmarklet

人力検索のウォッチリストの話。

せっかく autopagerize な感じになってるのに、項目を削除するとページがリロードされちゃうので、どこまで見てたか分からなくなって非常に使いづらい。
ずーーっと気になってたけど、一向に改善される気配はないので、Bookmarklet を書いてみた。
http://let.hatelabo.jp/a-kuma3/let/hJmfhdGO3ulD

(function () {

    if (window.location.hostname == 'q.hatena.ne.jp' && /\/watchlist$/.exec(window.location.pathname)) {

        var frm = document.getElementById('delete-target');
        if (! frm) {
            var forEach = Array.prototype.forEach;

            // target frame
            var frm = document.createElement("iframe");
            frm.id = 'delete-target';
            frm.name = 'delete-target';
            frm.style.width = 0;
            frm.style.height = 0;
            document.body.appendChild(frm);

            // display mode
            var prof = document.body.querySelector('.profile-account-container');
            var e = document.createElement('div');
            e.innerHTML = 'interactive delete mode';
            var s = e.style;
            s.position = 'absolute';
            s.padding = '2px 8px';
            s.right = 0;
            s.backgroundColor = 'red';
            s.color = 'white';
            prof.appendChild(e);

            // delete item with animation
            var eraseItem = function() {
                var li_ = this.parentNode;
                li_.style.transition = 'all 1.2s';
                li_.style.opacity = 0;
                var f = (function() {
                            var li = li_;
                            return function() {
                                var ul = li.parentNode;
                                ul.removeChild(li);
                            }
                        })();
                setTimeout(f, 1300);
            };

            // set target to delete form
            var changeTarget = function (context) {
                forEach.call(context.querySelectorAll('form.delete'), function (f) {
                    f.target = 'delete-target';
                    f.onsubmit = eraseItem;
                    // I don't need confirm.
                    var btn = f.querySelector('input[type="image"]');
                    if (btn) {
                        btn.onclick = function() {return true;};
                    }
                });
            };
            changeTarget(document.body);

            // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
            // http://caniuse.com/#feat=mutationobserver
            var MutationObserver = window.MutationObserver || window.WebkitMutationObserver;
            new MutationObserver(function (records) {
                records.forEach(function (record) {
                    changeTarget(record.target);
                });
            }).observe(document.body, { childList: true, subtree: true });

        }
    }
})();

削除するリクエストをフレームに飛ばして、ページのリロードをしないだけなんだけど。
うっとおしい confirm も削除。
ウォッチリストをまとめて整理するのには、ちょっと便利。

項目を削除した後に、autopagerize が走ると、削られた一項目分ずれて表示されるから、実は項目をひとつ見逃しちゃう、という欠点はあるのだけれど。
フレームの onload でレスポンスを拾って、最後の項目をリストの尻につければ良いんじゃないかという気もするけれど、地味に面倒なので割愛 :-)