ふにゃるんv2

もとは、http://d.hatena.ne.jp/Wacky/

オレオレ専用のはてぶWebアプリを作る

前回、ローカルアプリケーションキャッシュ機能を使って、Xmarksに替わる、オレ専用のブックマークWebアプリを作る - ふにゃるんを作った訳ですね。

それから更に調子に乗って、オレオレ専用のはてぶWebアプリを作ってみました。

何で作ろうと思ったか

iPodというかiPhoneには、元々はてぶアプリがあるんですが、出来るのはブックマークかWebブラウジングのみ。

iPodのはてぶアプリで、ブックマークしようとすると、以下の問題に突き当たります。

  1. 無線LANといえど、パソコンでWebブラウズする方が視認性が良いし速い。
    (現在の所、iPodのWebブラウズは補助的に使っている状態。未だにメインはパソコンなんですね)
  2. ブックマークする際、タグをiPodで打ち込むのは、恐ろしい苦行なり。
    (ブラインドタッチに慣れているので、思考と入力が一致しないのは、恐ろしく不便)
  3. パソコンでは、オレ専用のブックマークアプリを使って楽しているから、そっちで使いたい。
    (P4Dで、はてレジ(はてなブックマークを登録するツール)を作ってみました - ふにゃるんのことです)
  4. iPhoneなら常時ネット接続だが、iPodなので、常時ネット接続じゃないので、オフライン重視じゃないと困る。
    (オフラインサポートしていないニュース系アプリは即行削除行きだったり。:-P)


以上の理由と、手にした技術で遊んでみたいという強い欲求から、オレオレ専用な はてぶWebアプリを作ってみた次第です。

参考にしたWebサイト

今回参考にしたWebサイトは、以下の通りです。

使っている技術

参考にしたWebサイトでもわかる通り、今回使用した技術は、大体こんな感じです。

jQuery Mobile
前回は jQtouchでしたが、今回はjQuery Mobileです。
採用に特に意味は無く、一応本命と言われているので 試してみたくなっただけです。
Google Ajax Feeds API
今回、外部ドメインRSSデータを取得する必要がありまして、普通はCGIか何か置いて、CGIから外部ドメインRSSデータを取得したりするのがセオリーっぽかったんですが。
まぁ、これでも良いかな。と。
HTML5のローカルストレージ
ローカルに永続的にデータを格納できる技術として、ローカルストレージ技術とSQLを用いた技術があるようなんですが、今回は楽っぽい(キーバリューでOKなんですもん)ローカルストレージにしました。

ソースコード

てけとーではありますが、ソースコードを晒します。

<!DOCTYPE html>
<html manifest="test_hatebu.manifest">
<meta charset="UTF-8" />
<title>はてぶホットエントリをチェキ</title>
<link rel="stylesheet" href="lib/jquery.mobile-1.0a3.min.css" />
<script src="lib/jquery-1.5.min.js"></script>
<script src="lib/js_sprintf.js"></script>
<script src="https://www.google.com/jsapi?key=$ここに取得したキーを入れて" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
    function make_entry(feed){
        console.log("make_entry=%d", feed.entries.length);
        
        var ary = jQuery.map(feed.entries, function(n, i){
            var s = $.sprintf(  "<div class='ui-bar ui-bar-b'>                                      \
                                    %(no)d: %(title)s                                               \
                                </div>                                                              \
                                <div>                                                               \
                                    <div data-role='controlgroup' data-inline='true' align='right' data-type='horizontal'>      \
                                        <input type='checkbox' name='chk' id='chk-%(no)d' value='%(url)s'/>                     \
                                        <label for='chk-%(no)d' data-icon='start'>後で</label>                              \
                                        <span>&nbsp;</span>                                         \
                                        <a href='%(url)s' data-role='button' data-icon='arrow-r' target='_blank'>URL</a>    \
                                    </div>                                                          \
                                    <p>%(content)s</p>                                              \
                                </div>",
                { no: i+1, url: n.link, title: n.title, content: n.contentSnippet, detail: n.content });
            return s;
        });
        $("#rss").append(ary.join());
    }

    function load_entry() {
        console.log("load_entry");
        var feed_url = "http://b.hatena.ne.jp/hotentry.rss";
        var feed_content = null;
        try{
            console.log("no local storage[%s]", feed_url);
            var feed = new google.feeds.Feed(feed_url);
            feed.setNumEntries(100)
            feed.load(function(result) {
                feed_content = JSON.stringify(result.feed);
                localStorage[feed_url] = feed_content;
            });
            console.log("set local storage!!");
        }catch(e){
            console.log("sorry fail fetch:" + feed_url);
        }
        
        if(feed_content == null){
            feed_content = localStorage[feed_url];
        }
        var feed = JSON.parse(feed_content);
        make_entry(feed);
    }
    
    try{
        google.load("feeds", "1");
    }catch(e){
        console.log("fail google.load");
    }
    //google.setOnLoadCallback(load_entry);
    
</script>
<script type="text/javascript" charset="utf-8">
    console.log("custom script code!!");
    
    // 設定の為の初期化
    $(document).bind("mobileinit", function(){
        console.log("mobileinit");
    });
    
    // 普通の初期化
    $(function(){
        console.log("function!!");
        
        var clickTrigger = ($.support.touch)? "tap": "click";
        
        $("#call-mail").bind(clickTrigger, function(){
            //$("[name='select']:checked").each(function(){
            var chks = $(":checked").map(function(){
                return this.value;
            }).get();
            //alert("checkbox:" + chks.join(","));
            if(chks.length > 0){
                s = "subject=" + "after_check!!" + "&body=" + chks.join("\n");
                location.href = "mailto:$メアドを入れて?" + encodeURI(s);
            }
            return false;
        });
    });
    
    $('#main').live('pagebeforecreate',function(event){
        console.log("pagebeforecreate");
        // ページを作成する前に、はてぶエントリーを生成する
        // でないと、スマートフォンな外観にならないから
        load_entry();
    });

    $('#main').live('pagecreate',function(event){
        console.log("pagecreate");
    });
    
    console.log("end of script tag");
</script>
<script src="lib/jquery.mobile-1.0a3.min.js"></script>
</head>
<body> 

<!-- Start of first page -->
<div data-role="page" id="main">

    <div data-role="header" data-theme='d'>
        <h1>はてぶホットエントリ</h1>
        <a id="call-mail" href="#" class='ui-btn-right'>to メール</a>
    </div>

    <div data-role="content">
        <div id="rss"></div>
    </div>

    <div data-role="footer" data-theme='a' align='center'>
        <span>end of document&nbsp;</span>
        <a id="call-mail" href="#">to メール</a>
    </div>
</div>

</body>
</html>

あと、ローカルWeb化する為に、test_hatebu.manifest ファイルを同じフォルダに突っ込んでおきましょう。

CACHE MANIFEST
# rev1

CACHE:
lib/jquery.mobile-1.0a3.min.css
lib/jquery.mobile-1.0a3.min.js
lib/jquery-1.5.min.js
lib/js_sprintf.js

lib/images/ajax-loader.png
lib/images/form-check-off.png
lib/images/form-check-on.png
lib/images/form-radio-off.png
lib/images/form-radio-on.png
lib/images/icon-search-black.png
lib/images/icons-18-black.png
lib/images/icons-18-white.png
lib/images/icons-36-black.png
lib/images/icons-36-white.png

なお、lib/js_sprintf.js ファイルは、jQuery pluginの http://plugins.jquery.com/project/printf からゲットしたコードを置いています。

動かしてみる

WWWサーバーに適当に放り込んだファイルを、iPodSafariから参照すると、以下の画面が出て来ます。
(機内モードで、ちゃんと動いているのが判りますか?)

1
1 posted by (C)wacky


基本的に、「後で」にチェックを付けまくって、ヘッダもしくはフッタにある、「to メール」ボタンを押すと、チェックを付けたURLがメールの本文に適用される。
といった流れです。
一応オマケとして、「URL」ボタンを押すと、はてぶエントリのWebページに飛んでいきます。


例えば、2つほど、エントリに対して「後で」をチェックします。

2
2 posted by (C)wacky


ここで、「to メール」ボタンを押すと、メーラーが起動して、チェックしたURLが本文に適用されます。

3
3 posted by (C)wacky

後は、メールするだけです。
簡単ですね。


ちなみに、1回目の読み込みで、エントリのWeb作成に反映せず、2回目以降で成功したりするバグを抱えています。
が、とりあえず動いたので晒すという暴虐。

最後に

全体的に文字がバカでか過ぎるので、もちっとコンパクトにしたいなぁ。と思っています。特に、「後で」「URL」ボタンのデカさと言ったら…。ふぅ。


しかし、今回で2つですが、テキトーでも、それらしくアプリケーションのように振舞うWebソフトが出来るなんて、HTML5って便利な技術ですね。


ここまで便利に動くとなると、いわゆるガラケーと呼ばれる既存の携帯も、HTML5をサポートすれば良いのに。と、思ってしまいますね。
Flash Liteがあるので、もっと高度な遊びが出来るのは判りますが、HTML5は更に技術の敷居が低いので、開発者の裾野が広がると思うんですがねぇ。
(ハードをスマートフォン化するより、手っ取り早いと思うんだけどなぁ)