qooxdooの低レベルAPI

qooxdooの最大の特徴は、DOMやHTML、CSSなどを使わずに、用意されたAPIを用いたJavaScriptコードだけでWebアプリケーションが作成できることである。しかし、ときにはすべてをJavaScriptで書くことが少々煩わしいケースもある。そんなときのために、qooxdooではDOMやHTML要素を直接操作するための低レベルAPIが用意されている。

図1はqooxdooのアーキテクチャを表した図である(qooxdooの公式サイトより引用)。前回、前々回の例ではGUIツールキットを利用したWebアプリの作り方を紹介したが、qooxdooではそれだけでなくHTML要素の操作やイベント処理などを行うためのLow-Level層のAPI、そしてBOM(Browser Object Model)やDOM、XMLを操作するためのBrowser Abstraction層のAPIを利用することもできる。

図1 qooxdooのアーキテクチャ(qooxdooの公式サイトより引用)

低レベルAPIを利用してDOMを操作する

今回は、Browser Abstraction層のAPIを利用してBOMおよびDOMを操作する方法を紹介する。BOMはブラウザ依存のJavaScriptランタイム環境をラッピングし、クロスブラウザに対応したアプリケーションを作成するためのオブジェクトモデルである。BOMのクラス群はqx.bomパッケージで提供され、これを利用することでDOMの要素やネイティブオブジェクトなどを、ブラウザを意識しないで扱うことができる。

一方、DOMを扱うクラス群はqx.domパッケージに含まれている。このパッケージで提供されるのは、DOMの構成要素をqooxdooのクラスにラッピングしたものだ。たとえばqx.dom.ElementはDOMの各要素を表したクラスである。

Browser Abstraction層のAPIのみでアプリケーションを作る場合、アプリケーションの雛型は--typeオプションを使用してプロンプト1のように作成する(C:\workspaceフォルダに「lowlevel_app」という名前のアプリケーションを作成する場合)。

プロンプト1

> C:\qooxdoo-1.0.1-sdk\tool\bin\create-application.py --name=lowlevel_app --type=bom --out=C:\workspace
> cd C:\workspace\lowlevel_app
> .\generate.py build

--typeに"bom"と指定すると、GUIツールキットなどの余分なAPIを含まない雛型が生成される。この例の場合はC:\workspace\lowlevel_appがアプリケーションのフォルダであり、index.htmlをWebブラウザで開くと図2のようになっている。このページにフォーカスがある状態でキーボードの任意のキーをタイプすると、図3のようにタイプしたキーの種類が表示される。

図2 --type=bomとした場合に生成される雛型のトップページ

図3 タイプしたキーの種類が表示される

このindex.htmlのソースは次のようになっている。

リスト1

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <script src="qx-bom.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
  <h1>BOM application demo</h1>
  This tiny application demo shows the low-level API in action.

  <h2>Type ahead!</h2>
  <div id="logger"></div>

  <script type="text/javascript" charset="utf-8">
    // register callback
    qx.event.Registration.addListener(window, "ready", onReady);

    // executed when the application/scripts are loaded
    function onReady()
    {
      var logger = document.getElementById("logger");

      var loggerStyle = {
          "width" : "80%",
          "height" : "250px",
          "border" : "1px solid lightgrey",
          "overflow" : "auto"
      };
      qx.bom.element.Style.setStyles(logger, loggerStyle);

      // indicate startup
      logger.innerHTML += "Application ready ...";

      qx.bom.Element.addListener(document.body, "keydown", function(e) {
        logger.innerHTML += e.getKeyIdentifier() + "<br>";
      });
    }
  </script>
</body>
</html>

このページがロードされると最初にonReady()が呼び出されるので、この部分に初期化をはじめとしたアプリケーションの処理を記述すればよい。中身は一見すると通常の(qooxdooを使わない)JavaScriptだが、よく見るとところどころでqx.bomパッケージのクラスを利用していることがわかる。

たとえばqx.bom.element.Style.setStyles()は第1引数で指定されたDOM要素に、第2引数でMapオブジェクトとして渡されたスタイルを適用するというものだ。また、qx.bom.Element.addListener()はDOM要素にイベントを追加するためのメソッドである。このように、必要に応じてqooxdooのオブジェクトモデルやイベントモデルを混ぜて使える点が大きな特徴と言える。

続いて、リスト2のようなページ(DOMsample.htmlとした)を作ってみた。前述のindex.htmlと異なるのは、JavaScriptの中で新たに要素を作成してページのレイアウトを変えている点である。

リスト2 DOMsample.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <script src="qx-bom.js" type="text/javascript" charset="utf-8"></script>
</head>

<body>
  <h1>DOMを直接操作する</h1>

  タイトル:<input id="title" type="text" value="" size="50"/><br/>
  URL:<input id="url" type="text" value="http://" size="50"/>
  <input id="addButton" type="submit" value="追加" />

  <script type="text/javascript" charset="utf-8">
    // register callback
    qx.event.Registration.addListener(window, "ready", onReady);

    // executed when the application/scripts are loaded
    function onReady()
    {
      // div要素を作成
      var divElement = new qx.bom.Element.create("div");
      var divStyle = {
          "width" : "80%",
          "height" : "200px",
          "border" : "1px solid lightgrey",
          "overflow" : "auto"
      };
      qx.bom.element.Style.setStyles(divElement, divStyle);

      // リストを作成
      var listElement = new qx.bom.Element.create("ul");
      listElement.id = "linkList";

      var itemElement = new qx.bom.Element.create("li");
      var linkElement = new qx.bom.Element.create("a");
      linkElement.href = "http://journal.mycom.co.jp/";
      linkElement.innerHTML = "マイコミジャーナル";
      itemElement.appendChild(linkElement);
      listElement.appendChild(itemElement);

      divElement.appendChild(listElement);
      document.body.appendChild(divElement);

      // ボタンにリスナを追加
      var buttonElement = document.getElementById("addButton");
      qx.bom.Element.addListener(buttonElement, "click", function(e) {
        addLink();
      });
    }

    function addLink() {
      var title = document.getElementById("title").value;
      var url = document.getElementById("url").value;
      var list = document.getElementById("linkList");

      var item = new qx.bom.Element.create("li");
      var link = new qx.bom.Element.create("a");
      link.href = url;
      link.innerHTML = title;

      item.appendChild(link);
      list.appendChild(item);
    }
  </script>
</body>
</html>

ここではqx.bom.Element.create()というメソッドを使って要素を作成している。このメソッドは、引数にタグが指定されると、そのタグの要素を生成してqx.dom.Elementオブジェクトとして返す。qx.dom.Elementオブジェクトには、appendChild()によって子要素を追加することができる。これは通常のJavaScriptとまったく同じである。

ボタンがクリックされた際に呼び出されるリスナはqx.bom.Element.addListener()で設定しており、addLink()を呼び出すようにしてある。addLink()はテキストフィールドに入力された文字列とURLを使ってリンク(a要素)を作成し、それをリストアイテム(li要素)の子要素とした上で、リスト(ul要素)に追加する。

このページをWebブラウザで開くと、まず図2.6のように表示される。タイトルとURLを入力して[追加]ボタンをクリックすると、図2.7のようにリンクが追加される。

図4 WebブラウザでDOMsample.htmlを開いた様子

図5 ボタンをクリックすると新しいリンクが追加される

このように、qooxdooは通常のJavaScriptを拡張するライブラリとしても利用することができる。GUIツールキットを除いた低レベルAPIは、他のフレームワークと組み合わせて使いたい場合などに便利である。