この記事の目的は、バージョン 1.0 以降の Dojo JavaScript ツールキットを使って HTML ウィジェットを開発する際の基本を理解してもらうことです。記事ではまた、単純なウィジェットの例から次第に複雑なウィジェットの例へと進むなかで、ウィジェット開発の際によく直面する問題を解決していきます。
Dojo は、動的 HTML Web アプリケーションを開発するための JavaScript をベースとしたオープンソースのツールキットです。Dojo では標準的な HTML ウィジェットよりも複雑なウィジェットを簡単に作成することができます。Dojo に用意されたコンポーネントを使用することで、Web ユーザー・インターフェースの使い勝手、応答性、機能性が一段と向上します。また、Dojo が提供する下位レベルの API および互換層のおかげで、特定のブラウザーに依存しないアプリケーションを作成することができます。
ウィジェットの開発に取り掛かる前に、まずは開発環境をセットアップする必要があります。その方法は以下のとおりです。
- Dojo プロジェクト・サイトから、Dojo ツールキットの最新リリース・バージョン (dojo-release-1.x.x-src.zip または dojo-release-1.x.x-src.tar.gz) をダウンロードします (このサイトへのリンクは、「参考文献」を参照)。
- アーカイブの中身をフォルダーに解凍します。この際、dojo.js ファイルがどの場所に解凍されているかに注意してください。パッケージ・システムは、dojo.js がページにロードされてから、すべてのモジュールのロードを行います。
以上の作業が完了した時点で、フォルダーは図 1 に示すような構造になっているはずです。
図 1. 展開した dojo ファイルのフォルダー構造
Dijit は dojo をベースとしたウィジェット・システムで、その独自のテーマである tundra を介して、このパッケージに含まれるウィジェットすべてに共通のデザインおよびカラー・スキームを提供します。Dojox は Dojo ツールキットの拡張機能を集めた開発パッケージです。このパッケージは、共通コレクションには含まれていない機能を探している開発者のために提供されています。
Web サイトをブラウズすると、画面上で何百ものウィジェットを目にすることになります。Web ブラウザーのそれぞれのボタンはウィジェットです。テキスト入力ボックスもそれぞれウィジェットです。しかし、標準 HTML が提供するウィジェットは、入力ボックス、ボタン、ハイパーリンクに限られます。
Dojo ウィジェットはテキスト入力ボックスのようなアイテムに、よりユーザー・フレンドリーな機能 (例えば日付を選ぶためのグラフィカル・カレンダーなど) を追加します。しかも、追加機能を作成するベースとなる元のアイテムに手を付けることはありません。
Dojo ウィジェットは、可視の Web コンポーネントを再利用しやすくするためにカプセル化します。ウィジェットは、以下の 3 つのファイルによって定義されます。
- JavaScript ファイル。ウィジェットのロジックが含まれます。
- オプションの HTML ファイル。ウィジェットに HTML のようなテンプレートを提供するためのファイルです。
- CSS ファイル。通常はすべてのウィジェット (テーマ) に共通のファイルで、ウィジェットの HTML テンプレートに適用されるビジュアル・スタイルが含まれます。
リスト 2 に、基本的な HTML スケルトンを記載します。通常の Web ページでウィジェットをインポートする際には、このスケルトン・コードを使用することができます。
リスト 1. ウィジェットを Web ページにインポートする HTML コード
<html>
<head>
<title>Dojo Toolkit Test Page</title>
<style type="text/css">
/* CSS style code */
</style>
<script type="text/javascript" src="js/dojo1.2/dojo/dojo.js"
djConfig="parseOnLoad:true, isDebug:true"></script>
<script type="text/javascript">
/* Javascript code */
</script>
</head>
<body>
/* Widgets definition code */
</body>
</html>
|
最初の script タグは、単に dojo.js ブートストラップ・ファイルをロードすることによって Dojo ツールキットを初期化します。djConfig オブジェクトの parseOnLoad および isDebug の 2 つのプロパティーは、Dojo が実行時に確認する構成オプションのなかで、最もよく使われるものです。parseOnLoad はロード時のマークアップ構文解析をトグルする一方、isDebug はデバッグ・メッセージを有効または無効にします。この djConfig オブジェクトをグローバル変数として設定してから dojo.js ファイルをロードすることも可能です。
リスト 2. djConfig を使用してグローバル変数を設定するコード
<script type="text/javascript">
var djConfig = {
isDebug:true, parseOnLoad:true
};
</script>
<script type="text/javascript" src="js/dojo1.2/dojo/dojo.js"></script>
|
Dojo には、ファイル内にアプリケーションのクラスを構造化した上で、これらのファイルを dojo.require 関数でロードするためのパッケージ・システムがあります。この関数を使用することで、基本ライブラリーの dojo.js にはまだ提供されていない Dojo ツールキットのパーツをロードすることができます。
ウィジェットを作成するには、リスト 3 の行を追加してウィジェット宣言をインポートする必要があります。
リスト 3. ウィジェット宣言をインポートするコード
<script type="text/javascript">
dojo.require("widgets.Button");
</script>
|
これで、以下のコードを body セクションに挿入することができます。
<body>
<div dojoType="widgets.Button">My Button</div>
</body>
|
dojoType 属性によって、Dojo ツールキットは特殊な方法でタグを扱うことになります。ページのロード時に、Dojo パーサーは dojoType 属性に指定されたウィジェット宣言を調べて該当するウィジェットをインスタンス化し、それによって取得したウィジェット DOM ノードでタグを置き換えます。
それでは早速、TextBox ウィジェットの例を用いて JavaScript ファイル、テンプレート・ファイル、および CSS スタイル・ファイルを定義する方法を説明します。
まず始めに必要な作業として、TextBox.jsという JavaScript ファイルを作成し、ウィジェットの定義とロジックを含めてください (リスト 4 を参照)。
リスト 4. TextBox.jsという JavaScript ファイルの内容
dojo.provide("widgets.TextBox");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare(
"widgets.TextBox",
[dijit._Widget, dijit._Templated],
{
/** the template path */
templatePath: dojo.moduleUrl("widgets", "templates/TextBox.html"),
/** the input DOM node */
inputNode: null,
/** the label */
label: "",
/** onkeyup handler */
onKeyUp: function() {
// give a chance to the browser to update the DOM
setTimeout(dojo.hitch(this, this.validate), 0);
},
/** validate function */
validate: function() {
if ( this.inputNode.value === "Ok" ) {
// the text is correct
dojo.addClass(this.inputNode, "inputOk");
dojo.removeClass(this.inputNode, "inputError");
} else {
// the text is incorrect
dojo.removeClass(this.inputNode, "inputOk");
dojo.addClass(this.inputNode, "inputError");
}
}
}
);
|
dojo.provide() が新しいウィジェットの名前を定義してクラス宣言を登録します。リスト 4 で注意するのは以下の点です。
dijit._Widgetおよびdijit._Templatedは TextBox ウィジェットのスーパークラスです。templatePath、inputNode、labelはウィジェットの属性です。onKeyUp()およびvalidate()はウィジェットのロジックを定義する関数です。
次にテンプレート・ファイル、TextBox.html を定義します (リスト 5 を参照)。
リスト 5. TextBox.html の内容
<span class="textBox">
${label}:
<input
type="text"
class="inputOk"
dojoAttachPoint="inputNode"
dojoAttachEvent="onkeyup: onKeyUp">
</input>
</span>
|
${label} は、ウィジェット・インスタンスの label プロパティーに置き換えられます。
dojoAttachPoint 宣言によって、inputNode ウィジェットのプロパティーが入力タグに対応する DOM ノードに設定されます。
dojoAttachEvent 宣言によって、(入力ノードからの) onkeyup イベントが onKeyUp ウィジェットのメソッド呼び出しをトリガーします。
textBox クラスおよび inputOk クラスが参照するのは、TextBox.css ファイルに定義された CSS クラスの名前です。リスト 6 を参照してください。
リスト 6. TextBox.css に定義された CSS クラスの名前
.ibm .textBox {
margin: 5px;
padding: 5px;
background-color: #eee;
}
.ibm .inputOk {
border: 1px solid green;
}
.ibm .inputError {
border: 1px solid red;
}
|
クラス名はプロジェクト全体で一意でなければならないため、通常は CSS セレクターを使用することになります (この例でこれに該当するのは ibm です)。
これで、ウィジェットを HTML ページ上で作成することができます (リスト 7 を参照)。
リスト 7. HTML ページ上でウィジェットを作成するコード
<html>
<head>
<!-- page title -->
<title>TextBox Widget</title>
<!-- include the DOJO -->
<script type="text/javascript" src="../dojo-1.0.0/dojo/dojo.js"
djConfig="isDebug: true, parseOnLoad: true">
</script>
<!-- import DOJO base CSS, DIJIT theme, and widget CSS -->
<style type="text/css">
@import "../dojo-1.0.0/dojo/resources/dojo.css";
@import "../dojo-1.0.0/dijit/themes/tundra/tundra.css";
@import "templates/TextBox.css";
</style>
<!-- import DOJO stuff -->
<script type="text/javascript">
dojo.require("dojo.parser");
<!-- register our module path -->
dojo.registerModulePath("widgets", "../../widget");
<!-- import our stuff -->
dojo.require("widgets.TextBox");
</script>
</head>
<body class="tundra ibm" style="padding:5px">
<br/>
<!-- declare the DOJO widget -->
<div
dojoType="widgets.TextBox"
label="Name">
</div>
</body>
</html>
|
図 2 に、作成された TextBox ウィジェットを示します。
図 2. TextBox ウィジェット
Dojo では、宣言型モデルとプログラマチック・モデルの 2 つのプログラミング・モデルをサポートします。必要であれば、同じページで両方のモデルを使用することもできます。リスト 7 のウィジェットは、宣言型モデルで作成されています。
<div dojoType="widgets.TextBox" label="Name"></div> |
上記と同じウィジェットをプログラマチック・モデルで作成すると、リスト 8 のようになります。
リスト 8. プログラムによる TextBox ウィジェットの作成
<html>
<head>
<!-- page title -->
<title>TextBox Widget</title>
<!-- include the DOJO -->
<script type="text/javascript" src="../dojo-1.0.0/dojo/dojo.js"
djConfig="isDebug: true, parseOnLoad: true">
</script>
<!-- import DOJO base CSS, DIJIT theme, and widget CSS -->
<style type="text/css">
@import "../dojo-1.0.0/dojo/resources/dojo.css";
@import "../dojo-1.0.0/dijit/themes/tundra/tundra.css";
@import "templates/TextBox.css";
</style>
<!-- import DOJO stuff -->
<script type="text/javascript">
dojo.require("dojo.parser");
<!-- register our module path -->
dojo.registerModulePath("widgets", "../../widget");
<!-- import our stuff -->
dojo.require("widgets.TextBox");
</script>
<script type="text/javascript">
function createWidget()
{
var widget = new widgets.TextBox();
widget.label = "Name";
widget.startup();
}
</script>
</head>
<body class="tundra ibm" style="padding:5px">
<br/>
<!-- declare the DOJO widget -->
<script type="text/javascript">
createWidget();
</script>
</body>
</html>
|
前述したように、Dojo ウィジェットでは、特殊なクラス dijit._Widget を継承する Dojo クラスの宣言を行います。このクラスはウィジェットの基本的な振る舞いを定義し、すべてのウィジェット実装が共有する共通の関数を提供します。_Widget クラスが実装するタスクのなかで最も重要なものとして、以下の 4 つがあります。
createメソッドの定義。このメソッドは、ウィジェットがインスタンス化されるときに自動的に呼び出され、ウィジェットの作成に必要なすべてのステップを実行します。- いくつかの
templateメソッドの定義。これらのメソッドはウィジェットを実装するプログラムに特殊なフックを提供し、ある特定の作成フェーズで特殊な初期化アクションを実装する機会を与えます。 - 一連の
destroyメソッドの定義。ウィジェットに割り当てられたリソースは、これらのメソッドによってクリーンアップされます。 event managementメソッドの定義。これらのメソッドが、ウィジェットのメソッドを DOM ノード/メソッドの呼び出しイベントに接続します。
create メソッドは、ウィジェットを初期化する際に以下の基本的ステップを実行します。
ウィジェットに固有の ID が提供されていない場合には ID を作成する
すべての Dojo ウィジェットは固有の ID によって識別されなければなりません。ウィジェット ID はウィジェットをインスタンス化するときに指定されます。ID がない場合、Dojo は以下の形式の ID を作成します。
packageName_className_number
例えば、ボタンの場合には dijit_form_Button_0 のような ID が自動生成されます。
packageName はウィジェット・パッケージの名前で、パッケージ名に含まれるドットは例えば dijit_form といった具合にアンダーバーに置き換えらます。number は、ウィジェットごとに付けられる連番です。
ウィジェットをグローバル・ウィジェット・レジストリーに登録する
ウィジェットは後から dijit.byId メソッドを使って検索することができます。このメソッドは指定された ID に対応するウィジェット・オブジェクトを返します。レジストリーとは、dijit.registry_hash にあるグローバル空間に存在しているオブジェクトのことです。FireBug (「参考文献」を参照) などのデバッグ・ツールを使ってこのレジストリーをハッキングすることで、ウィジェット (例えば、リークしているウィジェットなど) を追跡することができます。
属性をマッピングする
ウィジェットのプロパティーは、ウィジェット・テンプレートのユーザー定義ノードに再マッピングすることができます。マッピングする属性とそのターゲットは、attributeMap オブジェクトにリストアップされます。このオブジェクトの各プロパティーは、以下のようにマッピングを定義します。
- プロパティーの名前は、設定する値の保存先とするウィジェットのプロパティー名を識別します。
- プロパティーの値は、ターゲット DOM ノードの保存先とするウィジェットのプロパティー名を識別します。空のストリングが指定された場合は、
domNodeが使用されます。
リスト 9 に一例を示します。
リスト 9. dojo ウィジェットの宣言
dojo.declare(
"MyWidget",
dijit._Widget,
{
// the attribute to map (name and value)
title: "myTitle",
// the DOM node to be used to set the
// title attribute to the "myTitle" value
titleNode: null,
// the attribute map
// the title attribute is mapped to the titleNode
attributeMap: {title: "titleNode"},
// the template string
templateString: "<div><span dojoAttachPoint=\"titleNode\"></span></div>",
|
上記の宣言によるウィジェット・テンプレートは以下のようになります。
<div><span title="myTitle"></span></div> |
基底クラス _Widget ではすでにいくつかの基本 HTML 属性 (ID、クラス、スタイルなど) をマッピングしているため、インプリメンターは attributeMap プロパティーをオーバーライドしないようにする必要があります。代わりに基底クラスの attributeMap プロパティーにインプリメンター独自の値をミックスさせる必要があります。リスト 10 は、_FormWidget クラスから抜粋した例です。
リスト 10. 基底クラスの attributeMap プロパティーへのカスタム値のミックス
attributeMap:
dojo.mixin(
dojo.clone(dijit._Widget.prototype.attributeMap),
{id:"focusNode", tabIndex:"focusNode", alt:"focusNode"}
),
|
ウィジェットの作成フェーズでは、インプリメンターが初期化フェーズで何らかの操作を実行できるように、いくつかのメソッドが呼び出されます。呼び出されるメソッドには以下のものがあります。
postMixInProperties: このメソッドは、ウィジェットのすべてのパラメーターがウィジェット・インスタンスのプロパティーとして設定 (ミックスイン) された後に呼び出されます。インスタンス化されたウィジェットによって提供されるプロパティーをベースとする場合には、このメソッドがさらなるプロパティーの初期化を実行する絶好の機会となります。buildRendering: ウィジェットのレンダリングを行う時点で呼び出されるメソッドです。このフックは、必要最小限のウィジェットを HTML テンプレートで拡張するdijit._Templatedミックスイン・クラスによって実装されます。インプリメンターはこのメソッドで、独自の実装を提供して_Templatedクラスのジョブを改良することができます。postCreate: このメソッドは、ウィジェットの DOM が用意され、ページに挿入された後に呼び出されます。インプリメンターはこの時点で、ウィジェットの DOM 構造を操作することができます。子ウィジェットはまだ起動されていません。startup: このメソッドが、ウィジェットを操作する最後のチャンスです。このメソッドが呼び出されると、子ウィジェットが起動されます。uninitialize: ウィジェットを破棄しているときに呼び出されるメソッドです。インプリメンターはこのメソッドで、自動クリーンアップ以外のクリーンアップを実行することができます。
テンプレート・メソッドはインプリメンターが提供することができますが、インプリメンターは、スーパークラスがそのテンプレート・メソッドを実装する可能性があることを忘れてはなりません。チェーンに含まれるすべてのクラスが正しく初期化されることを確実にするには、インプリメンターがスーパークラスのメソッド呼び出しを手動でコーディングする必要があります (リスト 11 を参照)。
リスト 11. スーパークラスのメソッド呼び出しの例
startup: function()
{
// call the superclass' method
this.inherited("startup", arguments);
// your code here
}
|
すべての作成メソッド (uninitialize を除くすべてのテンプレート・メソッド) に適用される通例として、スーパークラスのメソッドを最初に呼び出し、スーパークラスのアイテムが適切に初期化されてからアイテムを操作するようにしてください。
uninitialize メソッドには、これとは逆の規則が適用されます。
最後に言っておかなければならない startup メソッドに関する注意点が 1 つあります。startup メソッドは、ウィジェットが宣言によって作成されている場合には dojo.parser.parse メソッドによって自動的に呼び出されます。しかし、ウィジェットがプログラムによって作成されている場合、このメソッドは自動的には呼び出されないため、以下の例のように手動で呼び出す必要があります。
var w = new MyWidget({});
w.startup();
|
ウィジェットは作成された後、明示的な破棄要求が実行されるまで存続します。ウィジェットのライフ・サイクルの管理はすべてインプリメンターに任されますが、これにはウィジェットの破棄も含まれます。ウィジェットを破棄しなければ、ページ全体がクリーンアップされるまでウィジェットがリークすることになります。ウィジェットを破棄するメソッドには以下の 4 つがあります。
destroyRendering: ウィジェットのレンダリング・アイテムをクリーンアップします。インプリメンターが部分的なクリーンアップを必要としない限り、通常はこのメソッドが他の破棄メソッドによって呼び出されます。destroyDescendants: すべての子ウィジェットを破棄します。インプリメンターが部分的なクリーンアップを必要としない限り、このメソッドはdestroyRecursiveメソッドによって呼び出されます。destroy: ウィジェットのアイテムを破棄します (子ウィジェットは破棄しません)。destroyRecursive: ウィジェットのアイテムと子ウィジェットを破棄します。ウィジェットに内部ウィジェットも含まれる場合には、このメソッドを呼び出す必要があります。
ウィジェットに内部ウィジェットが含まれる場合 (例えば、ウィジェットのテンプレートにいくつかのウィジェットがある場合など)、インプリメンターは忘れずに子ウィジェットをトリガーし、何らかの方法でその子ウィジェットを破棄しなければなりません。その際、どの破棄メソッドを呼び出すかはウィジェットの使用側に決めさせることがないようにします。リスト 12 は、そのための方法の一例です。
リスト 12. ウィジェットの破棄をトリガーする例
uninitialize: function()
{
// destroy the descendants
this.destroyDescendants();
// call the superclass' method
this.inherited("uninitialize", arguments);
}
|
Dojo ウィジェットは、DOM ノードおよびオブジェクトの両方で発生する可能性のある外部イベントに反応することができます。このようなイベントを手動で接続するには、ウィジェットの connect メソッドを使用します。このメソッドのシグニチャーは以下のようになっています (このシグニチャーは dojo.connect メソッドと非常によく似たものです)。
connect: function(/*Object|null*/ obj, /*String*/ event, /*String|Function*/ method); |
あるいは、テンプレートで dojoAttachEvent 属性によって接続を宣言するという方法で、外部イベントを自動的に接続することも可能です。いずれの場合も、ウィジェットは内部で _connects 配列を使って接続を追跡します。すべての接続は、ウィジェットが破棄される時点で自動的に接続解除されます。このようにして、ウィジェットと DOM ノード間の参照が解除されます。
ウィジェットのライフ・サイクル期間中に、ある接続が不要になった場合、インプリメンターは disconnect メソッドを呼び出して手動で接続を解除することで、イベント処理を減らすことができます。
これまでの説明でおわかりのように、ウィジェットは dijit._Widget クラスを継承する必要があります。Dojo ウィジェットの基本的な振る舞いを定義して提供するこの基底クラスは、ウィジェットのレンダリング要素を作成するための buildRendering メソッドを定義します。例えば、ウィジェットのインプリメンターはこのメソッドでウィジェット・マークアップを作成し、そのマークアップをウィジェット DOM ノードに設定することができます。あるいは DOM API を使用してウィジェット構造を作成することも可能です。どちらの場合にしても、インプリメンターが何らかの方法で buildRendering メソッドをプログラムする必要があります。
Dojo では、強力な抽象化によって、ウィジェットのレンダリングの定義を、ウィジェットの振る舞いの実装から切り離します。それが、dijit._Templated ミックスイン・クラスです。インプリメンターがこのような抽象化を利用するには、リスト 13 に示すようにして _Templated クラスを継承する必要があります。
リスト 13. _Templated クラスを継承するコード
dojo.declare(
"widgets.MyWidget",
dijit._Widget, dijit._Templated
{
templatePath: dojo.moduleUrl("widgets", "templates/MyWidget.html"),
}
);
|
_Templated クラスが提供する独自の buildRendering 実装は、HTML に似た定義を利用します。この定義は、以下のいずれかの場所に配置することができます。
- 外部ファイル。このファイルは、templatePath プロパティーが参照します。
- 内部ストリング・プロパティー。この場合、テンプレートはウィジェット内の
templateStringプロパティーに直接定義されます。templateStringが指定されている場合は、templatePathは指定されているとしても無視されます。
1 番目の選択肢は、ウィジェットのソース・コードを最も簡潔に整理する方法となります。というのも、マークアップを別のファイルに作成し、読みやすいフォーマットにすることができる上に、ストリング連結について考慮する必要もなく、ストリング区切り文字がエスケープされることもないからです。その一方、2 番目の選択肢は、ブラウザーで別のファイルをロードしなくてもよいため、パフォーマンスに関してはこちらのほうが優れています。とは言え、Dojo には外部テンプレートをウィジェットのソース・コード内に内部化するビルド・ツールがあるので、ファイル・ロード時のパフォーマンスについては心配する必要はありません。
テンプレートは、ウィジェットのプロパティーを参照することによってパラメーター化することができます。この方法は、ウィジェットがマークアップに直接影響する構成パラメーターを公開する場合、あるいはマークアップを外部設定に応じて条件付きで生成しなければならない場合に役立ちます。ウィジェットのプロパティーを参照するために使う構文は、${propertyName} です。
テンプレートには他のウィジェットの宣言を含めることもできますが、これらの宣言が考慮されるようにするためには、ウィジェット開発者が widgetsInTemplate プロパティーを true に設定する必要があります。このプロパティーは、必要ない可能性のある処理をスキップするために、デフォルトでは false に設定されています。
テンプレートには、以下の 2 つの特殊な属性宣言を含めることができます。
dojoAttachPoint: このタグ属性を指定する場合、ウィジェットのプロパティー名に設定する必要があります。このタグに対応する DOM は、ウィジェットのプロパティーに設定されます。テンプレート内のタグには、1 つ以上のアタッチ・ポイントを設定できるものがいくつかあります。- dojoAttachEvent: このタグ属性は、DOM イベントがトリガーされたときにコールバックする必要があるウィジェットのメソッドをリストアップします。
リスト 14 に、テンプレートの一例を記載します。
リスト 14. 特殊な属性宣言が含まれるテンプレートの例
<span
class="textInputDefault"
dojoAttachEvent="onclick:_onClick">
<img
class="textInputIcon"
src="${constants.DEFAULT_ICON}"
dojoAttachPoint="_iconNode"/>
<input
class="textInputNode"
size="${size}"
type="${type}"
value=""
dojoAttachPoint="_inputNode, _focusNode"
dojoAttachEvent="onkeyup:_onKeyUp, onkeypress:_onKeyPress, onchange:_onChange"
/>
<span
class="textInputRight">
</span>
</span>
|
Tivoli Dynamic Workload Console と Dojo
TDWC (Tivoli Dynamic Workload Console) は、TWS (Tivoli Workload Scheduler) のグラフィカル・ユーザー・インターフェースです。このセクションでは、TDWC v.8.5 が Dojo の機能をどのように利用するかについて説明します。
TWS は、今日の複雑な業務環境でのワークロード管理を支援するために設計された生産自動化ソリューションです。スケジューリングする主な要素には、ジョブとジョブ・ストリームがあります。ジョブとは、実行可能ファイル、プログラム、コマンドなどのタスクのことです。ジョブ・ストリームとは、関連ジョブのコンテナーを表し、これらのジョブを実行時間、実行順序、並行性の制限、繰り返しという観点から編成します。TWS はジョブの実行計画を支援し、相互依存関係を解決し、それぞれのジョブを開始して追跡します。このようにするのは、ジョブはその依存関係が満たされると同時に開始されるためであり、これによってアイドル時間は最小限に抑えられ、スループットが大幅に改善されます。一連のジョブは必ずシーケンス通りに実行されます。そのため、あるジョブが失敗すると、TWS がリカバリー・プロセスに対処します。オペレーターが介入する必要はほとんど、あるいは一切ありません。
TDWC v.8.5 には充実した機能を備えたワークロード・エディターが組み込まれています。一貫して JavaScript で作成されたこのエディターは、Dojo ツールキットを使用しています。こうした実装のおかげで、できる限りブラウザー内部で実行されるコードを使用して、「インテリジェンス」と振る舞いをよりユーザーの感覚に近いものにすることが可能になっています。
TDWC に表示される TWS ジョブ・ストリームのプロパティー・パネルの一例を見てください。図 3 は、PAYROLL というジョブ・ストリームに定義された一般プロパティーの Web パネルです。
図 3. ジョブ・ストリーム PAYROLL の Web パネル
以前の記事「AWT (AUIML Web Toolkit): JavaScript と Dojo のための AUIML レンダラー」(「参考文献」を参照) では、AUIML ツールキットを使ってパネルを設計する方法、そして AWT (AUIML Web Toolkit) を使って JavaScript で論理コードを実装する方法を説明しました。図 4 に、AUIML パネルを示します。
図 4. AUIML パネル
Valid from フィールドに注目してください。このフィールドは AUIML エディターでは Edit Box, Date として定義されています。AWT はこの要素を、リスト 15 に記載する HTML コードで結合します。
リスト 15. 要素を結合するための HTML コード
<span type='text' dojoType='ajaxcommon.widgets.DateInputBox' id='validFrom'>
<script type='dojo/method'event='onValueChanged'>AWT.dispatchOnChange(this.id);</script>
</span>
|
リスト 16 は、ウィジェット ajaxcommon.widgets.DateInputBox の定義です。
リスト 16. ajaxcommon.widgets.DateInputBox を定義するコード
dojo.provide("ajaxcommon.widgets.DateInputBox");
dojo.require("ajaxcommon.resources.Images");
dojo.require("ajaxcommon.widgets._DateTimePicker");
dojo.require("ajaxcommon.widgets.picker.PickerInputBox");
dojo.require("ajaxcommon.widgets.picker.DatePicker");
dojo.declare(
"ajaxcommon.widgets.DateInputBox",
[ajaxcommon.widgets.picker.PickerInputBox,
ajaxcommon.widgets._DateTimePicker],
{
/** the picker icon */
pickerIcon: ajaxcommon.resources.Images.get()["CALENDAR_ICON"],
/** the picker disabled icon */
pickerDisabledIcon: ajaxcommon.resources.Images.get()["DISABLED_CALENDAR_ICON"],
/** the picker icon title */
pickerIconTitle: ajaxcommon.resources.Labels.get()["PICK_DATE"],
/** constraints */
constraints: {selector: "date", formatLength: "short", wideYear: true},
/**
* Constructor.
*/
constructor: function()
{
// even if the format length is short, ensure the wide year (yyyy)
// by overriding the datePattern
if (this.constraints.formatLength === "short" && this.constraints.wideYear) {
this.constraints.datePattern = this._getWideDatePattern();
}
// set the regex for the text
this.textRegExp = "^(" + dojo.date.locale.regexp(this.constraints) + “){0,1}$";
// set the regex message for the text
this.textRegExpMessage =
this._labels.format("DATE_INVALID_VALUE", {example: this._getExampleValue()});
// set the picker class
this.pickerClass = "ajaxcommon.widgets.picker.DatePicker";
},
/**
* Returns the date pattern with the wide-year (yyyy)
*/
_getWideDatePattern: function()
{
// get the bundle
var bundle = dojo.date.locale._getGregorianBundle();
// get the pattern
var pattern = bundle["dateFormat-short"];
// replace the yy to yyyy if not yet yyyy
if ( pattern.search(/yyyy/gi) === -1 ) {
// the year is not in the wide form
pattern = pattern.replace(/yy/gi, "yyyy");
}
return pattern;
},
/**
* Returns a string containing an example of accepted value.
*/
_getExampleValue: function()
{
// get a sample date object (my birthday!!!)
var d = new Date();
d.setDate(15);
d.setMonth(4);
d.setYear(1971);
// format the date in the current locale and return
return dojo.date.locale.format(d, this.constraints);
}
}
);
|
上記のコンストラクターによって、スーパークラス・ウィジェット ajaxcommon.widgets.picker.PickerInputBox (リスト 17 に定義) で宣言されたウィジェットのプロパティーを初期化することができます。
リスト 18 に、関連するウィジェット・テンプレートを記載します。
リスト 18. ajaxcommon.widgets.picker.PickerInputbox のウィジェット・テンプレート
<span
class="picker"
><span
tabindex="${tabindex}"
dojoType="${_textBoxWidget}"
dojoAttachPoint="_textNode,_focusNode"
required="${required}"
size="${size}"
minLength="${textMinLength}"
maxLength="${textMaxLength}"
regExp="${textRegExp}"
regExpReference="${textRegExpReference}"
regExpMessage="${textRegExpMessage}"
minWidth="${minWidth}"
></span
><span
dojoAttachPoint="_pickerButtonContainer">
<img
tabindex="${tabindex}"
src="${pickerIcon}"
dojoAttachPoint="_pickerButtonNode"
dojoAttachEvent="onclick:_onClick,onkeyup:_onKeyUp"
class="pickerButton"
title="${pickerIconTitle}"
/></span>
</span>
|
図 5 を見ると、ウィジェットのロジックをブラウザー側に委譲した場合の利点がわかります。つまりウィジェットは、値の設定中にエラーが発生すると、関連エラー・メッセージを表示し、ルック・アンド・フィールを変更するように実装されているのです。
図 5. ブラウザー側のウィジェット・ロジックを示すパネル
この記事では、バージョン 1.0 以降の Dojo JavaScript ツールキットを使用した HTML ウィジェット開発の基本概念について、最初に単純なウィジェット、そして次に複雑なウィジェット (TDWC v.8.5 で実装されたウィジェットなど) の例を用いて説明しました。また、Dojo ツールキットならではの利点についても明らかにしました。
次回の記事では、リッチ・インターネット・アプリケーションを開発する際によくあるパフォーマンスの落とし穴を検討し、私たちが主に Dojo ツールキットをベースに作成したベスト・プラクティスを使って問題に対処する方法を説明します・
- developerWorks blogs から developerWorks コミュニティーに加わってください。
- Dojo ツールキットの最新リリース・バージョン (dojo-release-1.x.x-src.zip または dojo-release-1.x.x-src.tar.gz) をダウンロードしてください。
- FireBug をこのプロジェクトの Web サイトからダウンロードしてください。

Marco は1999年から IBM Rome Tivoli Lab のスタッフ・エンジニアとして働いています。現在は TDWC の設計と開発に従事しています。彼は現在、Web 2.0 開発、特に Dojo ベースの技術やユーザー・エクスペリエンスの設計パターンなどに関心を持っています。

Roberto は 12 年間ソフトウェア開発の分野で働いており、これまでに開発者やアナリスト、Web インターフェース設計者、対話動作の設計者などを経験してきました。現在は Tivoli 組織で Tivoli Workload Scheduler 製品や Dynamic Workload Broker 製品のための Web ユーザー・インターフェースの設計に従事しています。そうしたことから、彼は要件の収集や設計の検証、販売を実現するための折衝など、顧客と直接やり取りする業務を頻繁に行っています。彼は developerWorks に何本かの記事を発表しており、IEEE の会議にも出席しており、またいくつかの学術協力も行っています。

Gianluca Perreca は IBM Rome Tivoli Lab のスタッフ・エンジニアです。彼は Tivoli Workload Scheduler 開発チームのメンバーであり、IBM Tivoli Workload Scheduler の Web インターフェースである IBM Tivoli Dynamic Workload Console の設計と実装に活躍しています。

Alessandro Scotti は IBM Tivoli Dynamic Workload Console のチーフ・デザイナーです。Tivoli Dynamic Workload Console は IBM Tivoli Workload Scheduler の Web インターフェースであり、AUIML ツールキットの他、AUIML や他の Web 2.0 技術を活用しています。彼はいくつかのオープンソース・プロジェクトの作成者であると同時に貢献者でもあり、主にグラフィカル・ユーザー・インターフェースのプログラミングやハイパフォーマンス・プログラミング、リアルタイム・プログラミングなどの領域で貢献しています。