Sencha Advent Calendar 2012 – 12月14日 BlogViewerやってくよー!

Sencha Advent Calendar 2012 12月14日分です :)
SenchaUG 勉強会 第2回@東京の使い回しになっちゃいますが、WordPressの簡易スマホ化をおさらいします ;)

Sencha SDK Tools

今回はプロジェクトを作成する際に、SenchaSDKToolsを使用します

$ cd SenchaTouchのSDKへのPATH
$ sencha app create アプリ名 アプリを作成したいフォルダへのPATH

こんな感じのプロジェクトが出来ます :)

今回のプロジェクトで作るファイル

  • app.js
    • 既存ファイルを編集
  • /app/controller/Article.js
    • 全体のController
  • /app/model/Article.js
    • ブログデータのModel
  • /app/store/Articles.js
    • Modelを格納するStore
  • /app/view/Detail.js
    • ブログ詳細ページ表示用のView
  • /app/view/List.js
    • ブログ一覧ページ表示用のView
  • /app/view/Main.js
    • 既存ファイルを編集

app.js

app.js内は非常にシンプルで、今回のアプリケーションに利用する各種部品の登録を行います。 viewportの設定はやっておくと、ブラウザで表示した際に領域稼げるので良いと思います。

ただ、もしかするとviewportの設定をしておくとブラウザからUA偽装してアプリケーションを表示する際に、Console.jsでエラー吐いて止まるかもしれないです。 :(

Ext.application({
    name: 'SenchaUG', // アプリケーションのネームスペース
    viewport: {
        autoMaximize: true // ブラウザで表示する際に、ヘッダーの検索バーを隠す
    },
    controllers: ['Article'], // Controllerの設定
    views: ['Main', 'List', 'Detail'], // アプリケーションで使用するViewの設定
    stores: ['Articles'], // アプリケーションで使用するStoreの設定
    models: ['Article'], // アプリケーションで使用するModelの設定
    launch: function() {
        Ext.fly('appLoadingIndicator').destroy();
        Ext.Viewport.add(Ext.create('SenchaUG.view.Main'));
    }
});
WordPress側に少し細工 :)

今回はWordPressにJSONを吐き出すように設定を行い、そのJSONを利用してブログデータの生成を行います。

WordPressの/wp-content/themes/テーマ名/functions.phpを編集して下記を追加すると、http://tnker.com?json=true というとうな形でJSONデータを取得することが可能になります。

global $wp;
$wp -> add_query_var('json');

function json_format($wp)
{
    if (get_query_var('json') != 'true') return;
    global $posts;
    header('Content-Type: application/json');
    echo json_encode($posts);
    exit;
}
add_action('wp','json_format');

/app/model/Article.js

上記でJSONを取得出来た際に確認すると分かるのですが、このような形で1つ1つ記事データのオブジェクトが配列に入った状態で渡されます。この配列の中に入っているオブジェクトがModel、このオブジェクトを格納している配列がStoreというとイメージしやすいかもしれませんね。

今回のBlogViewerで利用したいプロパティを名を確認してモデルを作成していきます :]

JSONデータから利用するのは、id, name, post_date, post_title, post_content を利用していきます。内容的には通常利用されるid、あとはどれも基本的なものですね。

Ext.define('SenchaUG.model.Article', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            {name: 'id',           type: 'int'},
            {name: 'name',         type: 'string'},
            {name: 'post_date',    type: 'date'},
            {name: 'post_title',   type: 'string'},
            {name: 'post_content', type: 'string'}
        ],
        proxy: {
            // 実際はここがWP側の記事一覧などの取得
            type: 'ajax',
            url: 'data/data.json',
            reader: {
                type: 'json'
            }
        }
    }
});

データの取得を行うにはproxyプロパティを設定する必要があります。 proxyのurlにローカルデータが指定してありますが、実際はjsonを取得するAPIのurlを指定します。

    proxy: {
        // 実際はここがWP側の記事一覧などの取得
        type: 'ajax',
        url: 'data/data.json', → 'http://tnker.com?json=true',

/app/store/Articles.js

取得したデータ(モデル)を格納しておくStoreを用意します。configプロパティで、このStoreで利用するModelのクラスを定義します。

また、autoLoadプロパティをtrueに設定しておくことにより、このストアがインスタンス化された際に自動的にデータの取得を行ってくれます。

Ext.define('SenchaUG.store.Articles', {
    extend: 'Ext.data.Store',
    config: {
        model: 'SenchaUG.model.Article',
    },
    autoLoad: true
});

/app/view/List.js

ブログ一覧のViewを作成します。
aliasプロパティを利用してxtypeを指定します。これは後ほど、アプリケーション全体のViewへこのListlViewを登録する際に、xtypeを利用して登録するため。

ここで使っているExt.Listは、Storeを利用して表示します。Store内にデータがある場合そのデータを利用して、指定したテンプレート内(itemTpl)に表示したいデータを指定します。(下記参照)

Ext.define('SenchaUG.view.List', {
    extend: 'Ext.List',
    alias: 'widget.articlelist',
    config: {
        itemId: 'articleList',
        store: 'Articles',
        cls: 'article-list',
        itemTpl: [
            '<div class="article-div">',
                '<h1>{post_title:ellipsis(28)}</h1>',
                '<div class="value">{post_content:ellipsis(100)}</div>',
            '</div>'
        ]
    }
});

{post_title:ellipsis(28)}は、記事のタイトルデータの文字列を28バイトでトリムしています。このitemTplはXTemplateで構成されており、このほかにも様々なフォーマットの書式が用意されています。 また、このフォーマット用の関数などを自分で作ることも可能です。:)

/app/view/Detail.js

ブログ詳細のViewを作成します。
aliasプロパティを利用してxtypeを指定します。これは後ほど、アプリケーション全体のViewへこのDetailViewを登録する際に、xtypeを利用して登録するため。

ここは、ListViewから渡された記事データの詳細表示に使用するViewになっています。 {post_content}が記事の詳細ページのコンテンツになっている。

Ext.define('SenchaUG.view.Detail', {
    extend: 'Ext.Container',
    alias: 'widget.articledetail',
    config: {
      cls: 'article-detail',
      itemId: 'articleDetail',
      scrollable: {
        direction: 'vertical'
      },
      tpl: [
        '<div class="detail-div">',
          '<h2>{post_title}</h2>',
          '<div class="value">{post_content}</div>',
        '</div>'
      ]
    }
});

/app/view/Main.js

ListViewおよびDetailViewで指定したxtypeをここで利用していきます。
items内でアプリケーション全体のツールバーを設置し、指定したxtypeを設定します。

Ext.define("SenchaUG.view.Main", {
    extend: 'Ext.Container',
    fullscreen: true,
    config: {
        layout: {
            type: 'card',
            animation: {type: 'slide'}
        },
        itemId: 'main',
        items: [{
            docked: 'top',
            xtype : 'titlebar',
            title : 'SenchaUG',
            items: [{
                    xtype: 'button',
                    itemId: 'backButton',
                    text: '戻る',
                    ui: 'back',
                    align: 'left',
                    hidden: true
                }]
            },
            {xtype: 'articlelist'},
            {xtype: 'articledetail'}
        ]
    }
});