Mojitoでビューを作る!

MojitoYUI3ライブラリ(Yahoo! User Interface Library)上に構築されたJavascriptフレームワークです。YUI3自体がハイスタックなライブラリであるため、Mojitoでも独自拡張なしに様々なことを実行可能です。

前回の記事でMojitoを触ってみました。今回は、Mojito(とYUI3)の各種機能を使ってみたいと思います。Mojitoを初めて触る方、インストール方法やプロジェクト構成を知らない方は、前回の記事も読んでみて下さい。

今回は、以下の機能を触り、ビューを作ってみます。

    • テンプレート
    • HTMLFrameMojit
    • binder
    • クライアントへのdeploy

 

 

初期設定

まずは適当なディレクトリに移動し、サンプルプロジェクトを作成し、サンプルmojitを作成します。


$ mojito create app sampe_app
$ cd sample_app
$ mojito create mojit Sample

sample_appディレクトリ直下にあるapplication.jsonを以下のように編集し、Sample mojitをiアプリ内でインスタンスとして登録します(使えるようにする)。application.jsonを次のように編集します。


[
    {   
        "settings": [ "master" ],
        "specs": {
            "sample": {
                "type": "Sample"
            }   
        }   
    },  
    {   
        "settings": [ "environment:development" ],
        "staticHandling": {
            "forceUpdate": true
        }   
    }   
]

ついでに、ルーティングの設定も行います。まずは、Sample mojitのindexメソッドへのルートを設定しておきます。routes.jsonを次のように編集します。


[{
    "settings": [ "master" ],
    "sample-index": {
        "verbs": ["get"],
        "path" : "/",
        "call" : "sample.index"
    }   
}]

sample_appディレクトリ直下に戻り、サーバを起動します。


$ mojito start

この時点で、http://localhost:8666へアクセスすると、Mojitoが作成した画面が表示されます。ここに表示されている内容は、mojits/Sample/controller.server.js内のindexメソッドを実行した結果です。ちなみに、表示されているテンプレートは、mojits/Sample/views/index.mu.htmlです。

表示内容の変更

表示内容を変更しましょう。変更するには、ロジック部分(mojits/Sample/controller.server.js)とビュー部分(mojits/Sample/views/index.mu.html)の両者を変更します。ここでは、繰り返し構造を表示してみたいと思います。

まずは、mojits/Sample/controller.server.jsを次のように編集します。ここでは、アシアルを紹介してみます。


YUI.add('Sample', function(Y, NAME) {
    Y.mojito.controllers[NAME] = {
        init: function(config) {
            this.config = config;
        },
        index: function(ac) {
            // ビューに渡す内容を設定する
           var data = { 
                'company'    : 'アシアル株式会社',
                'company_uri': 'http://www.asial.co.jp',
                'logo_uri'   : 'http://www.asial.co.jp/images/common/company_logo.png',
                'exectives'  : [ 
                    {'name': '田中正裕', 'position': 'CEO', 'blog_id': 3}, 
                    {'name': '森川穣'  , 'position': 'CTO', 'blog_id': 9}, 
                    {'name': '小林有佳', 'position': 'CFO', 'blog_id': 6}
                ],  
                'employees'  : [ 
                    {'name': '井川数志', 'blog_id': 28},
                    {'name': '松田淳'  , 'blog_id':  4}, 
                    {'name': '海原才人', 'blog_id': 10},
                    {'name': '中川善樹', 'blog_id':  7}  
                ]   
            };
            data['logo_html'] = '<a href="https://www.asial.co.jp' + data['logo_uri'] + ' &mode=1" class="popupimg"><img src="https://www.asial.co.jp' + data['logo_uri'] + '"></a>';
            // ビューに値を渡す
            ac.done(data);
        }
    };
}, '0.0.1', {requires: ['mojito']});

次にビューを編集します。mojits/Sample/views/index.mu.htmlを次のように編集します。会社名、URL、ロゴ、取締役、社員や各々のブログへのリンクを表示します。Mojitoでは様々なテンプレートエンジンを使用可能です。デフォルトでは、Mustacheが使われています(マニュアルはこちら)。


<div id="{{mojit_view_id}}">
    <h2>{{company}}</h2>
    <div class="info">
        <a href="{{company_uri}}">Home</a><br>
        <a href="https://www.asial.co.jp{{logo_uri}} &mode=1" class="popupimg"><img src="https://www.asial.co.jp{{logo_uri}}"></a>
        {{{logo_html}}}
    </div>
    <div class="executives">
        <h3>取締役</h3>
        <ul>
            {{#exectives}}
            <li>
                {{position}}: <span class="name">{{name}}</span>
                <a href="http://blog.asial.co.jp/{{blog_id}}">Blog</a>
            </li>
            {{/exectives}}
        </ul>
    </div>
    <div class="employees">
        <h3>社員</h3>
        <ul>
            {{#employees}}
            <li>
                <span class="name">{{name}}</span>
                <a href="http://blog.asial.co.jp/{{blog_id}}">Blog</a>
            </li>
            {{/employees}}
        </ul>
    </div>
</div>

ファイルを編集したので、サーバを再起動します。サーバの止め方は単純にプロセスを止めればOKです(単に「Ctrl + c」)。再度、sample_appディレクトリでサーバを起動します($ mojito start)。すると、次のような画面が表示されます。

ビューの使い方はいたって簡単です。テンプレートファイル内では、controllerでActionContext(controller内のac変数)のdoneメソッドに渡したオブジェクト内の変数(プロパティ)を表示できます。上記の例で使用した表示方法は次の通りです。

  • 変数名を波括弧2つでくくる
    例えば、companyを使いたいなら、{{company}}とします。この場合、変数を自動的にエスケープしてくれます。XSS対策にはもってこいの機能です。
  • 変数名を波括弧3つでくくる
    エスケープなしで表示します。つまりHTMLタグを表示できます。上記の例では、img_htmlを{{{img_html}}}として出力しています。
  • 繰り返し構造を使用する
    波括弧2つと、#と/を使います。例えば、employees配列を表示する場合、{{#employees}}〜{{/employees}}の間では、各要素の変数を順番に使用できます(forやforeachと同じ)。

ビュー切替

ビューをかなり簡単に作れることが分かったと思います。さらに、Mojitoではデバイス毎のビュー切替にも対応しています。index.mu.hmlをコピーしてindex.iphone.mu.htmlを作ってみましょう。これでiPhoneからアクセスすると、index.iphone.mu.htmlが使用されます。

早速確認してみます。Mojitoでは、デバイスの認識に2つの方法を提供しています。すなわち、ユーザエージェントとGETクエリです。ブラウザから確認する場合には後者の方法を使います。GETクエリにdevice=iphoneと入れると、iphoneのテンプレートを使用してくれます。

index.iphone.mu.htmlとindex.mu.htmlを区別するために、何らかの文字(iPhoneなど)を追加しておきます。http://localhost:8666?device=iphone にアクセスしてみましょう。iPhoneという文字が表示されていると思います。実際にiPhoneで接続できるなら、接続してみましょう。

このビュー切替はファイル名により制御されています。ファイルの命名規則は次の通りです。


{コントローラのメソッド名}.[{デバイス名}].{レンダリングエンジン名}.html

index.mu.htmlのmuはMustasheの頭文字2つです。また、デバイス名は省略可能です。指定できるデバイス名は現在のところ以下の通りです(サポートデバイス)。

デバイス・ブラウザ ファイル名の例
Opera Mini index.opera-mini.mu.html
iPhone index.iphone.mu.html
iPad index.ipad.mu.html
Android index.android.mu.html
Windows Mobile index.iemobile.mu.html
Plam index.palm.mu.html
Kindle index.kindle.mu.html
Blackberry index.blackberry.mu.html

HTMLFrameMojit

上記のテンプレートでは、HTMLの一部のみを記述し、実際にそれだけを出力しています。実際にHTMLのソースを見ると、DIVタグとその中身だけが表示されます。


<div id="yui_3_4_1_2_1340068746787_6">
    <h2>アシアル株式会社</h2>
    <div class="info">...</div>
    <div class="executives">...</div>
    <div class="employees">...</div>
</div>

HTMLタグ、BODYタグ、必要なJavascriptファイルなどをテンプレートに記述することも可能です。しかし、Mojitoではもっと便利な機能を提供してくれています。HTMLFrameMojitを使えば、HTMLの大枠や、javascriptファイル、clientへのスクリプトファイルのデプロイなどを実行できます。HTMLFrameMojitとは、Mojitoにデフォルトで組み込まれているmojitの1つです。HTMLの大枠を提供するという意味で、Frameという単語を使用しています(frameやiframeタグは使っていません、念のため)。

実際に使ってみます。applicationでHTMLFrameMojitを使用する際には、application.jsonでHTMLFrameMojitをインスタンスとして登録します。そして、HTMLFrameMojitの子インスタンスとして、他のmojitを登録します。実際に、Sample mojitをHTMLFrameMojitの子として登録してみます。


[
    {   
        "settings": [ "master" ],
        "specs": {
            "sample": {
                "type": "HTMLFrameMojit",
                "config": {
                    "title": "Sample App",
                    "child": {
                        "type": "Sample"
                    }   
                }   
            }   
        }   
    },  
    {   
        "settings": [ "environment:development" ],
        "staticHandling": {
            "forceUpdate": true
        }   
    }   
]

routes.jsonや他のファイルは一切編集しません。サーバを再起動し、再度http://localhost:8666ヘアクセスします。出力内容は表面上は変化しませんが、HTMLソースを確認するとずいぶんと異なります。


<!DOCTYPE HTML>
<html>
<head>
    <script type="text/javascript">var MOJITO_INIT=new Date().getTime();</script>
    <meta name="creator" content="Yahoo! Mojito 0.2">
    <title>Sample App</title>
</head>
<body>    
    <div id="yui_3_4_1_3_1340085944832_6">
        <h2>アシアル株式会社</h2>
        ...
    </div>
</body>
</html>

また、HTMLFrameMojitを使うことにより、client側へJavascriptファイルをダウンロードさせることも可能になります。Mojitoではデプロイといいます。デプロイの設定には、application.jsonでdeployプロパティをtrueとします。
application.jsonの一部を抜粋します。


            "sample": {
                "type": "HTMLFrameMojit",
                "config": {
                    "title": "Sample App",
                    "deploy": true,
                    "child": {
                        "type": "Sample"

これでcontrollerなどもclient側へダウロードされるようになります。実際にHTMLソースを確認すると、多数のJavascriptファイルを読み込ませるようになっています。


<!DOCTYPE HTML>
<html>
<head>
    <script type="text/javascript">var MOJITO_INIT=new Date().getTime();</script>
    <meta name="creator" content="Yahoo! Mojito 0.2">
    <title>Sample App</title>
    <script type="text/javascript" src="http://yui.yahooapis.com/combo?3.4.1/build/yui/yui-debug.js &..."></script>
</head>
<body>    
    <div id="yui_3_4_1_3_1340086591104_7">
        <h2>アシアル株式会社</h2>
        ...
    </div>
    <script type="text/javascript" src="/static/mojito/autoload/perf.client.js"></script>
    <script type="text/javascript" src="/static/mojito/autoload/mojito.common.js"></script>
    ...
    <script type="text/javascript" >
        ...
    </script>
</body>
</html>

作り方によっては、危険にもなりますが(セキュリティホールがある場合)、アプリの軽量化に資する仕組みでもあります。

Binder機能

HTMLFrameMojitを使うと、binder機能も楽に使用できます。Mojitoでは、DOMへのイベントリスナー登録や、DOMを変更する仕組みを、controllerやviewから切り離す構造があります。これがbinderです。mojits/Sample/binder/index.jsを編集し、アシアル取締役、社員をクリックすると、各々「取締役:名前」「社員:名前」と表示してみます。


UI.add('SampleBinderIndex', function(Y, NAME) {
    Y.namespace('mojito.binders')[NAME] = { 
        init: function(mojitProxy) {
            this.mojitProxy = mojitProxy;
        },  
        bind: function(node) {
            var me = this;
            this.node = node;
            node.all('.executives li').on('click', function(e) {
               var name = e.currentTarget.one('.name').get('text'); 
                alert('取締役:' + name);
            });
            node.all('.employees li').on('click', function(e) {
               var name = e.currentTarget.one('.name').get('text');
                alert('社員:' + name);
            });
        }
    };
}, '0.0.1', {requires: ['event-mouseenter', 'mojito-client']});

このファイルでは、bindメソッド内に必要な処理を記述します。bindメソッドに渡されるnodeオブジェクトはYUIのNodeオブジェクトです。YUIでDOMをラッパーしたものとなります。ご覧の通り、使い方は結構簡単です(通常のDOMやjQueryなどに似ているので)。

まとめ

アプリの作り方を工夫すれば、最初の画面のみWeb上から表示し、残りはclient側で実行させることも出来そうです。ユーザ体験を向上させ、使いやすいアプリを実現できると、なお面白いですね。