HTML要素を直接扱うHTMLレンダリングAPI
前回はqooxdooの低レベルAPIのうちqx.bomパッケージおよびqx.domパッケージで提供される機能を利用して、DOMを操作してUIを構築する方法を紹介した。これによってJavaScriptを利用した通常のWebアプリケーションと同様の使い勝手で、qooxdooで提供される様々な拡張機能を利用することができる。
なお、最近のアップデートでqooxdooのアーキテクチャには前回紹介したものからさらに若干の変更が加えられている。詳しくは公式のアナウンスを参照していただきたい。
今回はBOM/DOMではなく、その1階層上のAPIであるHTMLレンダリングAPIを利用したUIの構築方法を紹介したい。このAPIは、ネイティブのDOM要素をラップした各クラスによってブラウザの実装に依存しない形でUI要素の追加や変更、削除などを行う手段を提供する。一言で言えばqooxdoo独自のクラスを介してDOMを操作するということで、ブラウザ間の互換性を考慮する必要が無くなるという利点がある。さらに、多数のインスタンスを生成した場合の最適化が自動で行われるため、パフォーマンス面のメリットも大きい。
BOMを含むBrowser Abstraction層のAPIを利用する場合には、アプリケーションの雛型を作る際の--typeオプションに「bom」を指定したが、HTMLレンダリングAPIを利用する場合には代りに「native」を指定して次のようなコマンドを実行すればよい(アプリケーション名を「lowlevelapp2」とする場合)。これでGUIツールキットを含まない低レベルAPIまでを利用するアプリケーションが構築される。
プロンプト1
> C:\qooxdoo-1.0.1-sdk\tool\bin\create-application.py --name=lowlevel_app_2 --type=native --out=C:\workspace
> cd C:\workspacelowlevel_app_2
> .\generate.py all-source
nativeオプションを指定した場合に作成されるアプリケーションの構成は、GUIツールキットを利用する場合(つまりデフォルトのもの)と同様なので、sourceフォルダにあるindex.htmlがアプリケーションのトップページとなる。これをWebブラウザで開くと図1のようになっており、キーボードの任意のキーをタイプすると、タイプされたキーの種類が表示される。
アプリケーションのカスタマイズはsource\class\lowlevelapp2フォルダ以下にあるApplication.jsを編集することで行う。これもGUIツールキットを利用する場合と同じである。本稿の例ではリスト1のような内容にした。
リスト1
qx.Class.define("lowlevel_app_2.Application",
{
extend : qx.application.Native,
members :
{
/**
* メインメソッド
*/
main : function()
{
// Call super class
this.base(arguments);
// ログ出力を有効にする
if (qx.core.Variant.isSet("qx.debug", "on"))
{
qx.log.appender.Native;
qx.log.appender.Console;
}
/*
-------------------------------------------------------------------------
以下を修正してアプリケーションを作成する
-------------------------------------------------------------------------
*/
// タイトル要素を作成
var h1Element = new qx.html.Element("h1");
h1Element.add(new qx.html.Label().setValue("HTML要素を直接操作する"));
// 入力フィールドを作成
var titleElement = new qx.html.Input("text");
titleElement.setAttribute("size","50");
var urlElement = new qx.html.Input("text");
urlElement.setAttributes({"value" : "http://", "size" : "50"});
var buttonElement = new qx.html.Input("submit");
// リスト要素を作成
var divElement = new qx.html.Element("div");
var divStyle = {
"width" : "80%",
"height" : "200px",
"border" : "1px solid lightgrey",
"overflow" : "auto"
};
divElement.setStyles(divStyle);
var listElement = new qx.html.Element("ul");
listElement.setAttributes({"id" : "linkList"});
var itemElement = new qx.html.Element("li");
var linkElement = new qx.html.Element("a");
linkElement.setAttributes({"href" : "http://journal.mycom.co.jp/"});
linkElement.add(new qx.html.Label().setValue("マイコミジャーナル"));
itemElement.add(linkElement);
listElement.add(itemElement);
divElement.add(listElement);
// ボタンにリスナを追加
buttonElement.addListener("click", function(e) {
var item = new qx.html.Element("li");
var link = new qx.html.Element("a");
link.setAttribute("href", urlElement.getValue());
link.add(new qx.html.Label().setValue(titleElement.getValue()));
item.add(link);
listElement.add(item);
});
// 各要素をルート要素に追加
var root = new qx.html.Root(document.body);
root.add(h1Element);
root.add(titleElement);
root.add(new qx.html.Element("br"));
root.add(urlElement);
root.add(buttonElement);
root.add(divElement);
}
}
});
GUIツールキットが使えないので、ボタンなどのGUI部品はすべてHTML要素として構成する。HTMLの要素を表すクラスはqx.html.Elementであり、このコンストラクタにタグ名を渡すことで、渡されたタグの要素オブジェクトが生成される。ここでは<H1>や<div>、<ui>などの要素をこの方法で作成している。入力フォームについては、qx.html.Inputというクラスが用意されている。このコンストラクタに、type属性にあたる文字列("text"や"submit"など)を渡すことで、<input>タグが作成される。また、文字列はqx.html.Labelクラスを利用してラベルオブジェクトとして貼り付けることができる。
ボタンがクリックされた場合の処理は、ボタン要素に対してaddListener()でリスナを登録することによって実装する。ここでは新たにリスト要素(<li>タグ)とリンク要素(<a>タグ)を追加している。
最後に、ルート要素を作成してそこに各Elementオブジェクトを追加する。ルート要素を表すクラスはqx.html.Rootで、このコンストラクタにDOM要素のオブジェクトを渡すと、それに対応するHTML要素オブジェクトが生成されて、ルートとして設定される仕組みになっている。
では、再びWebブラウザでindex.htmlを開いてみよう。最初は図2のように表示されている。ここでテキストフィールドにURLとタイトルを入力して[追加]ボタンをクリックすれば、図3のように新たにリスト要素としてリンクが追加される(ただし、ラベルとして貼り付けているために行がずれてしまっている)。
今回はHTMLレンダリングAPIの使用例ということであえてGUIツールキットを利用しなかったが、GUIツールキットによるウィジェットを使いつつ、必要に応じてHTML要素を直接操作するといったことも可能だ。qooxdooの一番も魅力は何といってもGUIツールキットだが、それを除いたとしても洗練された機能が用意されており、非常に低レベルな部分からのカスタマイズにも対応している。目的に応じてさまざまなAPIを使うことができるのが大きな魅力である。