JAMADAM.COM

RSS Subscribe to my RSS feed

Stripe Calendar

Sep, 2010
Aug 1213141516171819202122232425262728293031 Sep 123456

Entry: ついったーのTLを60件に保つグリモンを作った

ついったーのTLを60件に保つグリモンを作った

Initial post: 2010.02.24 | Last modified: 2010.02.24

ついったーのタイムラインが放っておくと超長くなってブラウザが重くなるので、タイムラインのサイズを一定に保つグリモンスクリプトを作った。60件より古いtweetをjQueryでremoveしている。内部的にデータがどうなってるのか分からないので効果は不明だけどDOMが減るので軽くなるだろうという憶測。

これをインストール

// ==UserScript==
// @name           tweetReduce
// @namespace      http://jamadam.com/
// @description    Avoid Twitter Timeline size get too long
// @include        http://twitter.com/*
// ==/UserScript==

(function() {

    var $;
    var jversion = '1.2.6';
    var jexist = (typeof unsafeWindow.jQuery != 'undefined');
    var conflict = (jexist && unsafeWindow.jQuery.fn.jquery != jversion);
    // Add jQuery if not loaded
    if (! jexist || conflict) {
        var GM_JQ = document.createElement('script');
        GM_JQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/' + jversion + '/jquery.js';
        GM_JQ.type = 'text/javascript';
        document.getElementsByTagName('body')[0].appendChild(GM_JQ);
    }

    GM_wait();

    // Check if jQuery's loaded
    function GM_wait() {
        if (typeof unsafeWindow.jQuery == 'undefined' || unsafeWindow.jQuery.fn.jquery != jversion) {
            window.setTimeout(GM_wait,100);
        } else {
            if (conflict) {
                $ = unsafeWindow.jQuery.noConflict(true);
            } else {
                $ = unsafeWindow.jQuery;
            }
            letsJQuery();
        }
    }

    // All your GM code must be inside this function
    function letsJQuery() {
        var topid = $('#timeline li').eq(0).attr('id');
        window.setInterval(reduce, 5000);
        function reduce() {
            var newid = $('#timeline li').eq(0).attr('id');
            if (topid != newid) {
                topid = newid;
                console.log($('#timeline li').length);
                while ($('#timeline li').length > 60) {
                    $('#timeline li').eq(60).remove();
                }
            }
        }
    }
})();

Entry: commons markerの件数をgoogle検索結果に表示するグリモンをつくった

commons markerの件数をgoogle検索結果に表示するグリモンをつくった

Initial post: 2010.01.14 | Last modified: 2010.01.15

[2010.01.15追記] 無駄な処理が多かったのでソースを少し整理した。

恥ずかしながら、commons markerというサービスを最近まで知らなかった。前々から出来たらいいなと思っていたことにすごく近いので使い始めてみた。

ところで、はてなブックマークのFirefoxアドオンはとても便利で、とくにGoogle検索の結果にブクマ件数が表示されるのは、クリックすべきリンクのアタリをつけるのに大変便利なのですが、同じ発想でcommons markerの件数も参考データとして意味があるかもしれないと思い、早速グリモンスクリプトで実現してみた。

googleResultWithMarker.user.jsをインストール

image

// ==UserScript==
// @name           googleResultWithMarker
// @namespace      http://jamadam.com/blog/
// @description    googleResultWithMarker
// @include        http://*.google.co.jp/search*
// ==/UserScript==


(function() {

    var $;
    var jversion = '1.3.2';
    var jexist = (typeof unsafeWindow.jQuery != 'undefined');
    var conflict = (jexist && unsafeWindow.jQuery.fn.jquery != jversion);
    // Add jQuery if not loaded
    if (! jexist || conflict) {
        var GM_JQ = document.createElement('script');
        GM_JQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/' + jversion + '/jquery.js';
        GM_JQ.type = 'text/javascript';
        document.getElementsByTagName('body')[0].appendChild(GM_JQ);
    }

    GM_wait();

    // Check if jQuery's loaded
    function GM_wait() {
        if (typeof unsafeWindow.jQuery == 'undefined' || unsafeWindow.jQuery.fn.jquery != jversion) {
            window.setTimeout(GM_wait,100);
        } else {
            if (conflict) {
                $ = unsafeWindow.jQuery.noConflict(true);
            } else {
                $ = unsafeWindow.jQuery;
            }
            letsJQuery();
        }
    }

    // All your GM code must be inside this function
    function letsJQuery() {

        var array = $('#res li.g');
        var procExist = false;
        var i = 0;
        var loop = function() {
            if (i < array.length) {
                if (procExist) {return;}
                procExist = true;
                var href = array.eq(i).find('h3 a').attr("href");
                var pos = array.eq(i).find('span.gl');
                var url = encodeURIComponent(href);
                var jsurl = "http://commonsmarker.com/tools/latest_info?url=" + url;
                unsafeWindow["__jsonp__aD3jHjaf27mZQxt"] = function(a) {
                    if (! a || ! a.marks || ! a.marks.length) {
                        return;
                    }
                    $("<a>" + a.marks.length + " markers</a>")
                        .attr('href', "http://commonsmarker.com/page/" + href)
                        .css({
                            backgroundColor:"#f5d0d0",
                            color:"#ff0000",
                            fontFamily:"arial,sans-serif",
                            fontWeight:"bold",
                            marginLeft:"4px",
                            padding:"1px",
                            fontSize:"85%"
                        })
                        .insertAfter(pos);
                }
                $.ajax({
                    type: "GET",
                    url: jsurl,
                    dataType: "script",
                    complete: function() {
                        i++;
                        procExist = false;
                        loop();
                    }
                });
            }
        }
        loop();
    }
})();

commons markerの公式のインターフェースはまだ機能不足なため他のユーザーの動向がよく掴めなかったんだけど、こうしてスクリプトで簡単に件数を把握できるようにしてみて分かったことは、「全然利用されてない」ということでした。予想はしていたけど。

なお、commons markerはこの手の外部スクリプトへのインターフェースや仕様を一切公開していません。今回のスクリプトはとても強引な処理と憶測で実装しているので、サーバーの仕様が変わって動かなくなることが大いに予想されます。

Entry: グリモンでjQueryのコンフリクトを避けるテンプレート

グリモンでjQueryのコンフリクトを避けるテンプレート

Initial post: 2009.11.10 | Last modified: 2009.11.10

昨日のつづき。

グリモンスクリプトでjQueryを使うとき、他のスクリプトでロードされたjQueryの別バージョンとのコンフリクトを避けるためのテンプレート。

(function() {
        
    var $;
    var jversion = '1.3';
    var jexist = (typeof unsafeWindow.jQuery != 'undefined');
    var conflict = (jexist && unsafeWindow.jQuery.fn.jquery != jversion);
    
    // Add jQuery if not loaded
    if (! jexist || conflict) {
        var GM_JQ = document.createElement('script');
        GM_JQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/' + jversion + '/jquery.js';
        GM_JQ.type = 'text/javascript';
        document.getElementsByTagName('body')[0].appendChild(GM_JQ);
    }
    
    GM_wait();
    
    // Check if jQuery's loaded
    function GM_wait() {
        if (typeof unsafeWindow.jQuery == 'undefined' || unsafeWindow.jQuery.fn.jquery != jversion) {
            window.setTimeout(GM_wait,100);
        } else {
            if (conflict) {
                $ = unsafeWindow.jQuery.noConflict(true);
            } else {
                $ = unsafeWindow.jQuery;
            }
            letsJQuery();
        }
    }
    
    // All your GM code must be inside this function
    function letsJQuery() {
    
    }
})();

a

Entry: グリモンでjQuery使ったらTwitterがバグった件が解決した

グリモンでjQuery使ったらTwitterがバグった件が解決した

Initial post: 2009.11.08 | Last modified: 2009.11.08

jQuery & Greasemonkey

Twitterの公式ページに適用するためのGreasemonkeyスクリプトにjQueryを使おうと思ったら、しばらくうまく行かなかった。原因は、TwitterページがすでにjQueryの旧バージョンをロードしていたというだけ。今回はたまたま自分のスクリプトがバージョンに依存しない内容だったので、if文でjQueryの存在確認をしてからロードすることで解決した。

(function() {

    // Add jQuery if not loaded
    if (typeof unsafeWindow.jQuery == 'undefined') {
        var GM_JQ = document.createElement('script');
        GM_JQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js';
        GM_JQ.type = 'text/javascript';
        document.getElementsByTagName('body')[0].appendChild(GM_JQ);
    }
    
    // Check if jQuery's loaded
    function GM_wait() {
        if (typeof unsafeWindow.jQuery == 'undefined') {
            window.setTimeout(GM_wait,100);
        } else {
            jQuery = unsafeWindow.jQuery;
            letsJQuery();
        }
    }
    GM_wait();

    // All your GM code must be inside this function
    function letsJQuery() {
        
    }
})();

Entry: text-overflow:ellipsis

text-overflow:ellipsis

Initial post: 2009.06.21 | Last modified: 2009.06.22

以前にこんなエントリ書いたり、こんなjQueryプラグイン作ったりしたけど、それってCSSだけでできるんじゃん!

http://www5e.biglobe.ne.jp/~access_r/hp/css/css_text_019.html

text-overflow
テキストがオーバーフロー(領域を超えてしまう事)する際にオーバーフローしたテキストを「...」で省略することが出来ます。

しかも属性名と値などのキーワードも思い描いたまんまじゃん。ただし、省略記号を有効にする指定はtext-overflow: ellipsis;だ。以前にもちゃんとググったつもりだったけど、英語の情報無視してたかなあ。

ただしFirefoxは未対応なので依然としてJavascriptでのハックは必要。また、text-overflowはIEのみの対応のようで、SafariやOperaはそれぞれの拡張属性を併記して対応できる。

a.width-limited {
    display:block;
    overflow: hidden;
    white-space:nowrap;
    -webkit-text-overflow: ellipsis; // Safari
    -o-text-overflow: ellipsis; // Opera
    text-overflow: ellipsis; // IE
}

Entry: Javascriptオフ対策、その2

Javascriptオフ対策、その2

Initial post: 2009.06.12 | Last modified: 2009.06.12

検索とタグクラウドもノースクリプトで利用できるようにした。ページナビゲーションはまだない。

JS用に用意した部品のDOMをNoscriptな人に見せないために、最初は<script></script>内に書けばいいのかと思ったら失敗。<script>タグは<noscript>タグのnotでは全然なかったのだ。考えたこともなかったけど、<script>タグ内にはスクリプトしか書いちゃいけない、とのこと。今さらながら。

スクリプト用のDOMはスクリプトで書くしかないのかと思い、document.writeの列挙が頭をよぎったものの、メンテナンス性に配慮してjQueryのappendだのprependだののDOM操作で何とかする。それでも、文字のエスケープの問題もあるし、本来HTMLで書くべきものをJavascriptで書き出すのはやはり手間がかかる。でもまあいいか。

と思っていたのが昨日の話で、今日、あっけない結論に達する。まあ、ここに書くまでもないことかも。

<div class="dom_for_script" style="display:none"></div>
<script type="text/javascript">
//<![CDATA[
$(".dom_for_script").show();
//]]>
</script>

Entry: jQueryでCtrl + 左クリック

jQueryでCtrl + 左クリック

Initial post: 2009.06.05 | Last modified: 2009.06.05

ブログのリンクを、Ctrl + 左クリックのときはjavascriptで処理しないように変更した。event.metakeyでmacのコマンドキーにも対応。

$(selector).live('click', function(event) {
    
    // jQueryのliveメソッドと右クリックにまつわるバグを回避
    if (event.which != undefined && event.which != 1) {return}
    
    // Ctrl+左クリックの場合はキャンセル
    if (event.metaKey) {return}

    // ここに目的の処理
});

Entry: ブックマーク

Entry: ブックマーク

Entry: AJAXデータの取得先URLをどう管理するかという話

AJAXデータの取得先URLをどう管理するかという話

Initial post: 2009.06.01 | Last modified: 2009.06.01

AJAX満載のサイトでアンカーに紐づいたAJAXデータの取得先URLをどう管理するかという話。with jQuery1.3.2。

HTML

<a href="./path/to/parmalink.html">通常リンク</a>
<a href="./path/to/snippet.html" class="widget-opener">動的コンテンツ</a>

Javascript

$('a.widget-opener').live('click', function () {
    $.get($(this).attr('href'), function(html){
        //appendなりprependなり
    });
    
    return false;
});

上記の場合、javascriptオフの人が「動的コンテンツ」を叩くとHTMLスニペットやjsonテキストが画面いっぱいに広がるページに遷移してしまったりする。 また、検索クローラーはリンク先のページを収集してしまうかもしれない。

かといって、href="#"とでもして、すべてのアンカーにidをふって、script内でURLを関連づけていくのも煩雑だ。

HTML

<a id='id1' href="#" class="widget-opener">記事1</a>
<a id='id2' href="#" class="widget-opener">記事2</a>
<a id='id3' href="#" class="widget-opener">記事3</a>

Javascript

url.id1 = './path/to/snippet1.html';
url.id2 = './path/to/snippet2.html';
url.id3 = './path/to/snippet3.html';

そこで、アンカータグのonclickとjQueryの$.data()メソッドでAJAX URLをインラインで管理するようにしてみた。 $.data()はDOM要素に紐づいたデータを管理することが目的という、本件におあつらえ向きなメソッド。

HTML

<a href="#" class="widget-opener" onclick="$.data(this, 'ajaxURL', './ajax1.html')">記事1</a>
<a href="#" class="widget-opener" onclick="$.data(this, 'ajaxURL', './ajax3.html')">記事2</a>
<a href="#" class="widget-opener" onclick="$.data(this, 'ajaxURL', './ajax3.html')">記事3</a>

Javascript

$('a.widget-opener').live('click', function () {
    $.get($.data(this, 'ajaxURL'), function(html){
        //appendなりprependなり
    });
    
    return false;
});

onclickとliveでバインドしたイベントとの実行順が気になったけど、意図した順番に実行されている。ここで念のためonmousedownとかに逃げてしまうと、 今度は.trigger()が使えなくなってしまうのでonclickしかない。実行順が覆るケースがあるようなら、click.not_inlineというようにnamespacedイベントを利用して onclickイベントとの実行順を制御することもできる。

また、パーマリンクが存在するアンカーであれば、当然hrefにそれをかける。

<a href='./parmalink1.html' class="widget-opener" onclick="$.data(this, 'ajaxURL', './ajax1.html')">記事</a>

こうすることで、新規タブでリンクを開く可能性に配慮した仕組みも実現できる。実際、このブログの「最近の記事」のボタンは左クリックで新規ウィジェットを起動するけど、コンテキストメニューから新規タブでパーマリンクを開くこともできる。そして、この2つのURLをひとつのアンカータグ内で管理している。

まあ、HTML内に書くのには$.data()はちょっとだけ汚らしいというのは認める。