トップ » 技術記事 » Adobe AIR と ExtJS の入門(4) - Adobe AIR と Ext JS で作るTODOボード

Adobe AIR と ExtJS の入門(4) - Adobe AIR と Ext JS で作るTODOボード はてなブックマーク数 このエントリーをブックマークに追加

今回は、Adobe AIR と Ext JS を使った連載のまとめとして、TODOボードを作ってみようと思います。ここ数回、Adobe AIR (JavaScript) でよく使われる JavaScript のライブラリ、Ext JS を紹介しています。Ext JS を使うと、リッチなUIを使った Web アプリケーションを比較的簡単に作成できます。メッセージボックスなどもいちいちカッコよく、グリッドやパネルのレイアウトも手軽に作成できます。

ここで作るもの

ここで作るのは、気軽にTODOをメモすることができる掲示板風のボードです。

http://aoikujira.com/demo/hakkaku/rc/20080427_todoboard.png

TODOボード開発の準備

TODOボードですので、プロジェクト名は適当に todobard としました。

単純なツールですので、単純にファイル1つで構成したいのですが、Adobe AIR を使う場合は、セキュリティの制約を考慮するために、AIR API を直接使うメインファイルと、Ext JSを使うためのUIファイルで、主に2パートに分けます。そして、プログラムを見やすくするために、HTMLとJavaScriptでファイルを分けることにします。

すると、使用するライブラリの他に、メインファイルの todobard.html/todoboard.js と ui.html/ui.js の4つのファイルを作りました。ライブラリを含めると、非常にファイルが多くなります。

そして、必要なライブラリなどを用意しましょう。ここでは、Ext JSを使いますので、Ext JS のアーカイブを、プロジェクトの lib ディレクトリの ext というディレクトリにコピーしました。また、AIR の機能を利用しますので、AIR SDK の lib ディレクトリにある AIRAliases.js もプロジェクトの lib ディレクトリにコピーしておきます。

プロジェクトのファイル構成をまとめてみます。

[プロジェクトの構成]

+ todobard
| - todoboard.html   .. メインHTMLファイル
| - todoboard.js     .. メインプログラム(JavaScript)
| - ui.html        .. UI を記述したHTMLファイル
| - ui.js          .. UI を記述するプログラム(JavaScript)
| - <lib>
  | - AIRAliases.js      .. AIR API を使うために利用
  | - <ext>              .. Ext JS のライブラリをコピー
    | - ..

メインファイルの作成

では、TODOボードのメインファイルから作っていきましょう。メインファイルは、HTMLファイルです。Adobe AIR では、メインファイルのセキュリティは、Application sandbox となっており、AIR のコア機能をフルに利用することができます。しかし、eval() メソッドなど動的な要素が使えなくなってしまうので、Ext JS を使った画面設計などは、UI.html という別ファイルに記述することにします。

そのため、メインファイルの役割は、以下の2つです。

  • Ext JS を利用するファイル ui.html の取り込み
  • ローカルへの保存機能(AIR API)を提供する関数の定義

Ext JS のフル機能を使うためには、Non-application sandbox で実行する必要があります。そのために、iframe に sandboxRoot を指定します。この指定を、http から始めると、セキュリティサンドボックスを切り替えることができるのです。

また、AIR API は、Application sandbox でしか利用することができないので、このメインファイルに記述します。ただ、HTMLの中に記述してしまうと編集しづらくなってしまうので、todoboard.js というJavaScriptファイルに記述することにしました。

file:todoboard.html

<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>

<title>AIR + Ext JS で TODOボード</title>
</head><body>
  <!-- ui.html の取り込み -->
  <iframe id="UI" src="ui.html"

    sandboxRoot="http://example.com" documentRoot="app:/"
    style="width:100%; height:100%; border:none">
  </iframe>
  <!-- スクリプトの取り込み -->

  <script src="lib/AIRAliases.js"></script>
  <script src="todoboard.js"></script>
</body>
</html>

次に、todoboard.js を見ていきます。ここでは、AIR APIを使った関数を定義しています。ここで定義しているのは、loadFromLocal() と saveToLocal() の2つです。そして、これを、Non-application sadbox で使えるようにするため、parentSandboxBridge に登録します。

file:todoboard.js

// [program] 一行掲示板メインプログラム
// [sandbox] アプリケーションサンドボックス(Application sandbox)
// -------------------------------------------------------------------
// APIを使う関数を宣言し、
// クラシック・サンドボックスから利用できるように登録
var public_obj = {};
public_obj.saveToLocal   = saveToLocal;
public_obj.loadFromLocal = loadFromLocal;
var e = document.getElementById("UI");
e.contentWindow.parentSandboxBridge = public_obj;
// -------------------------------------------------------------------
// 関数の定義
var my_so = air.SharedObject.getLocal("todoboard"); // ------ (*1)
function saveToLocal(data) {
  my_so.data.saveData = data; // --------- (*2)
}
function loadFromLocal() {
  return my_so.data.saveData; // --------- (*3)
}

saveToLocal() と loadFromLocal() でやっているのは、非常にシンプルです。SharedObject という機能を使って、データを読み書きしているのです。この SharedObject は、Flash にもある機能で、ローカル領域に、オブジェクトを手軽に保存することができるようになっています。

使い方としては、まず、上記プログラムの(*1)のように、「air.SharedObject.getLocal()」で、SharedObject のオブジェクトを取得します。そして、(*2) のように、オブジェクトの data プロパティの任意の変数名に、保存したいデータを代入します。これで、ローカル領域にデータを保存することができます。そして、(*3) では、ローカル領域からデータを読み取ります。見ての通り、変数を参照しているだけです。

Adobe AIR を使えば、ローカルファイルを読み書きすることもできますが、SharedObject を使うことで、より手軽にデータを保存することもできるというのが分かると思います。

UIファイルの作成

では、次に、Ext JS を使ったUI定義ファイルを見ていきましょう。UIでは、フォームとグリッドを作成します。まずは、ライブラリの取り込みや、ui.js ファイルの取り込みを行う ui.html を見ていきます。ui.html では、Ext JS のライブラリの取り込みと、ui.js の取り込みをしています。そして、フォームとグリッドを配置するため、div タグを2つ定義しています。

file:ui.html

<!-- UIのためのファイル -->
<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<!-- ExtJS ライブラリの取り込み-->

<script src="lib/ext/adapter/ext/ext-base.js"></script>
<script src="lib/ext/ext-all-debug.js"></script>
<link rel="stylesheet" type="text/css"
      href="lib/ext/resources/css/ext-all.css"/>

<!-- UI記述プログラムの取り込み-->
<script src="ui.js"></script>
</head><body>
<div id="form_div"></div>
<div id="grid_div"></div>

</body></html>

HTMLファイル自体は、たいしたことがないので、次に、グリッドとフォームを定義している ui.js を見てみましょう。少し長いので、どんな内容が書かれているのか外観してから、再度細かい部分を見ていきます。

file:ui.js

// [program] 一行掲示板UI記述用プログラム
// [sandbox] クラシックサンドボックス(Non-apllication sandbox)

Ext.onReady(function(){
  // 親で定義された関数を使う
  // 保存されているデータの読み込み
  var save_data = window.parentSandboxBridge.loadFromLocal();
  if (save_data == undefined) { save_data = []; }
  // グリッドへのデータ反映
  function updateGrid() {
    data_store.loadData(save_data);
  }
  //------------------------------------------------------------------
  // フォームの作成
  // フォームに表示するフィールドの定義 --- (*1)
  var field_items = [
    {
        id:"title_txt",
        fieldLabel: 'タイトル',
        allowBlank:false
    },{
        id:"comment_txt",
        fieldLabel: 'コメント',
        allowBlank:false,
    }
  ];
  // フォーム下のボタンの定義 --- (*2)
  var form_buttons = [
      {
        text: '保存',
        handler: function() { // ボタンをクリックした時のイベント
          var title_txt   = Ext.get("title_txt");
          var comment_txt = Ext.get("comment_txt");
          save_data.unshift([
            title_txt.getValue(),
            comment_txt.getValue()
          ]);
          window.parentSandboxBridge.saveToLocal(save_data);
          updateGrid();
          Ext.Msg.alert("","保存しました");
          form.getForm().reset();
        }
      },{
        text: 'リセット',
        handler: function() { form.getForm().reset(); }
      }
  ];
  // フォームの作成
  var form = new Ext.FormPanel({
    title: '入力フォーム',
    labelWidth: 75,      // ラベルの幅
    frame:true,
    bodyStyle:'padding:5px 5px 0',
    width: '100%',
    height: 150,
    defaults: {width: '100%'},
    defaultType: 'textfield',
    items: field_items,    // 表示フィールドの指定
    buttons: form_buttons  // フォーム下のボタンの指定
  });
  form.render('form_div');
  //------------------------------------------------------------------
  // グリッドの作成
  // Storeオブジェクトの作成 --- (*3)
  var data_store = new Ext.data.SimpleStore({
    fields: [
        {name:"name"},
        {name:"comment"}
    ]
  });
  data_store.loadData(save_data);
  // GridPanel の作成 --- (*4)
  var grid = new Ext.grid.GridPanel({
    title:"一行TODOボード",
    width:'100%',
    height:350,
    stripeRows: true,
    store: data_store,
    columns: [
      {header:"名前", width:100, dataIndex:"name", sortable:true},
      {header:"コメント", width:450, dataindex:"comment", sortable:true}
    ]
  });
  grid.render('grid_div');
});

それでは、詳しく見ていきましょう。まず、2回目以降に実行されたとき、ローカル領域に保存されているデータを読み込みます。これは、iframe を定義している親のHTMLで定義された関数を利用します。parentSandboxBridge に定義されたオブジェクトを介することで、AIR API が利用可能になるという訳です。

  // 親で定義された関数を使う
  // 保存されているデータの読み込み
  var save_data = window.parentSandboxBridge.loadFromLocal();

次に、フォームの定義です。Ext JS では、どのようなコントロールを表示するのかその設定を定義しておいて、これをクラスの生成時に引数として渡すことで、簡易にフォームやグリッドなどのコンポーネントを作成することができます。

  //------------------------------------------------------------------
  // フォームの作成
  // フォームに表示するフィールドの定義 --- (*1)
  var field_items = [
    {
        id:"title_txt",
        fieldLabel: 'タイトル',
        allowBlank:false
    },{
        id:"comment_txt",
        fieldLabel: 'コメント',
        allowBlank:false,
    }
  ];
  // フォーム下のボタンの定義 --- (*2)
  var form_buttons = [
      {
        text: '保存',
        handler: function() { // ボタンをクリックした時のイベント
          var title_txt   = Ext.get("title_txt");
          var comment_txt = Ext.get("comment_txt");
          save_data.unshift([
            title_txt.getValue(),
            comment_txt.getValue()
          ]);
          window.parentSandboxBridge.saveToLocal(save_data);
          updateGrid();
          Ext.Msg.alert("","保存しました");
          form.getForm().reset();
        }
      },{
        text: 'リセット',
        handler: function() { form.getForm().reset(); }
      }
  ];
  // フォームの作成
  var form = new Ext.FormPanel({
    title: '入力フォーム',
    labelWidth: 75,      // ラベルの幅
    frame:true,
    bodyStyle:'padding:5px 5px 0',
    width: '100%',
    height: 150,
    defaults: {width: '100%'},
    defaultType: 'textfield',
    items: field_items,    // 表示フィールドの指定
    buttons: form_buttons  // フォーム下のボタンの指定
  });
  form.render('form_div');

プログラム中の(*1)では、フォームに表示するフィールドを定義しています。id を定義すると、あとから、その id を使ってそのコンポーネントにアクセスできるようになります。fieldLabel には、テキストを指定できます。

(*2)の部分では、ボタンやこれをクリックした時の動作を定義しています。クリックした時の動作は、handler に指定します。フォームをリセットするときは、「form.getForm().reset()」しています。もし、Web にデータをポストしたいときは、「form.getForm().submit()」と記述します。ここでは、フォームのデータを取得して、ローカルに保存しますので、submit は使いません。

そして、グリッドを定義しているのが、以下の部分です。グリッドでは、まず、Store オブジェクトを作成し、これをグリッドに設定することでグリッドにデータを表示することができます。

  // グリッドの作成
  // Storeオブジェクトの作成 --- (*3)
  var data_store = new Ext.data.SimpleStore({
    fields: [
        {name:"name"},
        {name:"comment"}
    ]
  });
  data_store.loadData(save_data);
  // GridPanel の作成 --- (*4)
  var grid = new Ext.grid.GridPanel({
    title:"一行TODOボード",
    width:'100%',
    height:350,
    stripeRows: true,
    store: data_store,
    columns: [
      {header:"名前", width:100, dataIndex:"name", sortable:true},
      {header:"コメント", width:450, dataindex:"comment", sortable:true}
    ]
  });
  grid.render('grid_div');

まとめ

以上、Adobe AIR と Ext JS 2.0 を使って、TODOボードを作成してきました。ここ数回の連載を振り返って、Ext JS を使うことで高度なコンポーネントが、利用できることが分かりました。しかし、Adobe AIR を使う際には、セキュリティサンドボックスに気をつけなければならないことも分かったと思います。

まだまだ、Ext JSについては、日本語のドキュメントが少ないのですが、本家サイトを見ると、サンプルも見やすく一新され、使い方のドキュメントも、今後、増えていくだろうと思います。

本連載が、Ext JS と Adobe AIR を始める上で参考になれば、幸いです。

Series Navigation«Adobe AIRとExtJSで一番簡単なコンポーネントの使い方

このサイトについて

八角研究所
株式会社八角研究所のWEBサイトですよー。 いろんなものを創り出すことのできる環境をコツコツ構築中。 いったい、いつになったらできるのか。 この技術情報サイトもそのための活動の一環のつもり。

執筆者紹介

クジラ飛行机

クジラ飛行机

くじらはんど(http://kujirahand/)にて、日本語プログラミング言語「なでしこ」(IPA未踏ユース採択)、テキスト音楽「サクラ」(OSPオンラインソフト大賞入賞)など多くのオンラインソフトを開発。著書に「Flexプロフェッショナルガイド」「なでしこ公式バイブル」、「一週間でマスターするActionScript3.0」など。

TrackBack URL :