目次


カスタム Dojo アプリケーションを作成する

Comments

はじめに

最近、私たちは Web 2.0 Dojo プロトタイプの開発を完了しました。このプロトタイプは広範な機能を備えており、情報管理の新しい機能も含まれています。私たちはこのアプリケーションを確実に使いやすいものにするため、私たちはユーザー・エクスペリエンス・チームと協力しました。画面については本格的なルック・アンド・フィールにするため、グラフィカル Web デザイナーが設計しています。

この記事では、このプロトタイプの Web 2.0 開発で私たちが得た経験を文書にします。Web 2.0 は比較的新しい技術なので、取り掛かるのが難しかったり、必要に応じたカスタマイズの方法がわからなかったりするものです。私たちの Dojo アプリケーションでは、グラフィック・デザインを製品ラインのブランド設定と一貫したものにする必要があったため、既製のルック・アンド・フィールを導入しませんでした。このため、Dojo でのカスタマイズが必要になりました。カスタマイズはほとんどの開発者が最終的に長い時間を費やすことになる作業ですが、開発者がカスタマイズの正確な方法をわかっていない場合は、なおさら時間がかかります。

この記事で重点とするのは Dojo アプリケーションのカスタマイズなので、必要となるウィジェットやサンプルに記載するウィジェットすべての属性について詳しく説明することはしません。また、この記事では読者に Dojo と CSS に関する基本知識があることを前提とします。記事に記載するサンプルのベースとなっているのは、Dojo 1.1.0 です (「参考文献」にリンクを記載しています)。

Dojo アプリケーションの作成

設計手法

ソフトウェア・エンジニアとしての経験を積んでいる私たちは、OO (Object Oriented) 手法を使用して開発を進めるのに慣れています。そのため、この Web 2.0 アプリケーションで目的としたのは、長年 Java™ プログラミングで実践してきた原則に従ったものにすることです。この目的は、Dojo ウィジェットとテンプレート・パターンを JavaScript/Dojo オブジェクトと併せて使用することによって、おおよそのところ達成できることがわかりました。

Dojo ウィジェットとテンプレート・パターンの使用

私たちは、カスタム・ウィジェットを作成しました。このウィジェットは JavaScript クラスで構成され、レンダリングには HTML テンプレートを使用します。こうすることにより、単にグローバル JavaScript 関数を使用する HTML ファイルを作成するよりも多くの OO 手法をアプリケーションに適用できます。このカスタム・ウィジェットではさまざまな機能を実現しました。具体的には、明確に定義されたウィジェットによるオブジェクトの分離、必要に応じて DOM を更新するウィジェットを使用した HTML の動的コンテンツ、そしてカスタム・ウィジェットを使って異なる HTML ID を生成することによる、同じ HTML テンプレートの複数インスタンスの実現などです。さらに、このように作成したカスタム・ウィジェットを拡張すれば、より特殊化したバージョンを追加することもできます。

リスト 1 にカスタム・ウィジェットの JavaScript ファイルの一部を抜粋します。このファイルは、dijit._Widget および dijit._Templated をベースに作成されたものです。

リスト 1. カスタム・ウィジェットの JavaScript ファイル
dojo.provide("mywidgets.MyWidget");
// put any other requires the widget needs here
dojo.declare(
  'mywidgets.MyWidget',
  [dijit._Widget, dijit._Templated],
{
  widgetsInTemplate: true,

templatePath: dojo.moduleUrl( "mywidgets",
"../templates/mywidgets/templateMyWidget.html");
// put any other variables and methods for this widget here
// can also override methods from the base classes here

});

このテンプレートには HTML タグだけでなく Dojo ウィジェットも含まれているため、widgetsInTemplate 属性は Dojo に対し、テンプレート・ファイルを解析する必要があることを伝えます。続いて、このウィジェットが指定の HTML テンプレートを使用してレンダリングすることを、templatePath 属性が Dojo に伝えます。new mywidgets.MyWidget() によって作成されるインスタンスを使用するなどして、ウィジェットがインスタンス化されると、DOM の中でこのオブジェクトが挿入される位置にテンプレートの HTML がレンダリングされます。

リスト 2 に、このウィジェットの HTML テンプレート・ファイルを記載します。

リスト 2. HTML テンプレート
<div class="templateMyWidget">
    <!-- Other Widgets and HTML can be included here -->
<button dojoType="dijit.form.Button" id="myButton_${id}"
label="My Button" dojoAttachPoint="myButton"></button>
</div>

上記のサンプルでは、ID に変数置換を使用しています。これは、コードがボタンにアクセスするときにボタンの ID を使用しなければならない場合に備えるためです。${id}dijit._Widget クラスから継承される ID 属性の値に置き換えられます。この ID は一意に決まる値なので、テンプレートではこれを ID の一部として使用し、複数のウィジェットをインスタンス化する場合には、各インスタンスの ID がユニークになるようにします。また、このサンプルには dojoAttachPoint 属性も組み込みました。これによって、ウィジェット内に DOM ノードを指す属性が作成されます。したがって、ウィジェット (例えば、myWidgetObj) へのアクセス権があれば、myWidgetObj.myButton を使用して DOM ノードにアクセスすることができます。ユーザーはこの ID を知る必要はありません。この ID 属性を使わなくても、システムが要素に対してユニークな ID を作成するからです。システムによって生成された ID は、myWidgetObj.myButton.id を使用して取得することができます。

Dojo ソース・コードをダウンロードすると、Dojo ウィジェットも上記の説明のとおりにコーディングされていることに気付くはずです。それぞれの Dojo ウィジェットごとに、JavaScript ファイルと、それに関連付けられた HTML ファイルがあります (通常はどちらも同じファイル名です)。テンプレートは、ウィジェットの JavaScript ファイルが置かれているディレクトリーと同じレベルにある templates というディレクトリーにあります。例えば、Button ウィジェットの JavaScript ファイルが <dojo_root>\dijit\form\Button.js だとすると、そのテンプレート・ファイルは <dojo_root>\dijit\form\templates\Button.html となります (<dojo_root> は、Dojo コードをダウンロードしたディレクトリーです)。

JavaScript および Dojo オブジェクトの使用

プロトタイプに取り掛かり始めた当時、私たちには十分な JavaScript の経験がありませんでした。しかしそれでも、プロトタイプを使うことで JavaScript の Object による、OO 原則を適用した開発を行うことができます。Dojo には私たちが使った方法よりも適切な方法として、dojo.declare 構文を使用して独自のクラスを定義する方法が用意されています。developerWorks の記事「Java 開発者にとっての Dojo の概念」(「参考文献」を参照) を是非、一読してください。あらゆるプロトタイプと同じく、このプロトタイプの要件も常に初期設計にまで影響してくることから、コードは煩雑になってしまいました。もっと多くのデザイン・パターンを採用していればよかったと後悔しています。デザイン・パターンに関する記事は数多くあり、そのなかには JavaScript および Dojo の例も記載されています。お勧めの記事は、「MVC with JavaScript」(「参考文献」を参照) です。

エラー処理

Java コードと同じく、JavaScript でも例外を処理します。エラーを処理するには、JavaScript の例外処理を使用することをお薦めします。

JavaScript での try/catch 処理 (リスト 3 を参照) は、Java コードとよく似ています。スタック・トレースは、例外オブジェクトで確認することができます。

リスト 3. try/catch 処理
try {
     // your logic
}catch(e){
     // error handling
}

例外は、Java プログラミングと同様に JavaScript のメソッドからスローすることができます。

リスト 4. 例外のスロー
if( <test for error condition> ) throw "meaningful error message";

Dojo の開発環境

  • 出発点 — Dojo サンプル/デモおよびテスト・コード: Dojo の開発を開始するには、時間も手間もかかりません。Dojo には任意の Web ブラウザーで実行することが可能なサンプルが豊富にあり、必要に合わせてそれを変更すればよいだけだからです。サンプルのほとんどは、Dojo ソース・コード内の tests ディレクトリーに置かれています。
  • 統合開発環境 (IDE): このプロジェクトを開始した時点では、Ajax/Dojo のサポートはほとんど皆無だったので、私たちはすべての開発を Eclipse ベースの IDE で行いました。Java 開発はすべて、この IDE で行っているためです。JavaScript や Dojo 向けのコードを支援するプラグインもいくつか見つかりましたが、サンプル・コードから逸脱しなければならない場合には、実際の Dojo クラスを読んでその使用方法を理解しなければならないことがほとんどでした。大幅な調整が迫られたのは、JavaScript ではコンパイル時のチェックが行われないという点です。コンパイル時にチェックが行われないということは、実際にバグがあるパスを実行するまでは、バグが見つからないことを意味します。
  • ヘルプ — Dojo コミュニティー: Dojo は非常によく使われているため、大規模なサポート・コミュニティーがあります。数多くのフォーラムでは、他の開発者たちが質問を投稿したり、問題に対するコード・ソリューションを提供したりしています。フォーラムに投稿されたサンプルが役立ったことは少なくありません。直接役に立たなかったとしても、これらのサンプルが、解決しようとしている問題に取り組む上でのヒントになったことは度々でした。
  • デバッグ — Firebug プラグイン: このプロトタイプの単一の Web ブラウザーとして、私たちは Mozilla Firefox を選びました。そのために追加したのが、Firebug プラグインです。Firebug はさまざまなサイトからダウンロードすることができます (「参考文献」にリンクを記載しています)。Firebug には、HTTP リクエスト/レスポンスをその送受信時刻と併せてログに記録する機能があります。また、JavaScript ファイルにブレークポイントを設定してデバッグを行える他、HTML、CSS、および DOM コードを調査/編集することも可能です。Firebug は、Dojo ウィジェットで使用されているスタイル属性を調べる上でも大いに役立ちます。

    さらに、Firebug は「console」という名前のグローバル変数を Web アプリケーションに追加します。この変数には debuginfowarnerrorlog など、ログおよびトレース用の多数のメソッドがあります。これらのメソッドはコンソールに、トレース・メッセージの JavaScript ファイル名と行番号と併せてメッセージを書き込みます。私たちは条件付きトレースを有効に設定し、グローバル属性を使ってコンソール・トレースのオン/オフを切り替えられるようにしました。

ここで 1 つアドバイスできることとして、私たちが dojo.require ステートメントを使用して独自のウィジェットを組み込んだとき (リスト 5 を参照)、明示的なスクリプト src ステートメントを追加するまでは (リスト 6 を参照)、コンソールのトレース・メッセージのファイル名と行番号は有効にならないことがわかりました。

リスト 5. dojo.require ステートメントによるウィジェットの組み込み
dojo.require("acme.MyWidget");
リスト 6. 明示的なスクリプトsrc ステートメントの追加
<script type="text/javaacript"src="widget/MyWidget.js"></script>

Dojo アプリケーションのカスタマイズ

私たちはいくつかの JavaScript フレームワークを検討しました。実際に必要だったのは、Dojo より多少上のレベルのフレームワークだったものの、Dojo には正しいビルディング・ブロック、カスタマイズ・ポイント、そして大規模なサポート・コミュニティーのすべてが備わっていました。

カスタマイズ方法

最終的に、Dojo をカスタマイズして使用することに決めました。このカスタマイズ・プロセスにはさまざまな側面があります。Dojo ウィジェットのルック・アンド・フィールをカスタマイズする最も単純な方法は、カスタム・スタイルシート (CSS) を使用することです。あるいは、Dojo ウィジェットのメソッドをオーバーライドしたり、特殊な振る舞いに対応するように既存の Dojo ウィジェットをサブクラス化するという方法や、独自のウィジェットを作成するという方法もあります。このセクションでは、このプロトタイプで使用しているさまざまなカスタマイズの方法について説明します。

注: このリストには、アプリケーション用に実際に開発した内容のサブセットを記載します。この記事には記載していないその他多くのカスタマイズは、現在、知的所有権 (IP) のプロセスにあります。

Dojo ウィジェットのスタイル変更

Dojo には、そのまま使用できる基本スキンとして、soria、tundra、nihilo の 3 つがあります。これらのスキンは、アプリケーションの全体的な HTML body タグの class 属性に指定することで、ベースとして使用することもできます。この場合、選択したスタイルを独自の CSS で上書きできるようになります。CSS 全体を一から作成することもできますが、アプリケーションが多くのウィジェットを使用する場合、このプロセスには時間がかかります。Dojo ウィジェットを事前定義されたスキンで表示するには、<dojo_home>/dijit/themes/themeTester.html (<dojo_home> は、Dojo ソース・コードをダウンロードしたディレクトリー) にある Dijit Theme Tester を実行してください 。

Dojo ウィジェットのテンプレートには、カスタム・スタイルシートを定義する際に使用できるクラス属性が含まれていますが、これらのスタイル名に関するドキュメントはどこにも見つかりませんでした。ウィジェットのクラス名を見つけるのに便利な手段は 2 つあります。まず 1 つは、ウィジェットに関連付けられたテンプレート .html ファイルを調べることです。dijit.form.Button ウィジェットのテンプレート・ファイルは、リスト 7 のような内容になっています。

リスト 7. dijit.form.Button ウィジェットのテンプレート
<div class="dijit dijitReset dijitLeft dijitInline"
    dojoAttachEvent="onclick:_onButtonClick,onmouseenter:_onMouse,onmouseleave:
  _onMouse,onmousedown:_onMouse"
    waiRole="presentation"
    ><button class="dijitReset dijitStretch dijitButtonNode
dijitButtonContents" dojoAttachPoint="focusNode,titleNode"
        type="${type}" waiRole="button" waiState="labelledby-${id}_label"
        ><span class="dijitReset dijitInline ${iconClass}" dojoAttachPoint="iconNode"
             ><span class="dijitReset dijitToggleButtonIconChar">✓</span
        ></span
        ><div class="dijitReset dijitInline"><center class="dijitReset dijitButtonText"
id="${id}_label" dojoAttachPoint="containerNode">${label}</center></div
    ></button
></div>

スタイルを設定する場合、テンプレートのクラス属性の値が関わってきます。${} で囲まれたクラスの値 (${iconClass} など) は、Button タグに指定された iconClass 属性の値に置き換えられます。

上記のサンプルでは、ボタンに表示されるテキストのスタイルを設定するために dijitButtonText を使用しています。したがって、テキストを青色で表示するとしたら、以下のコードをスタイルシートに組み込むことになります。

リスト 8. ボタンのテキストを青色の表示に変えるコード
.dijitButtonText
{
   color: blue;
}

さらに具体的に、スタイルの修飾を追加することもできます。詳細なスタイル設定は、クラス名が他のウィジェットでも使用されている場合には適切な対処法です。例えば、.dijitButtonTextComboButton テンプレートと DropdownButton テンプレートでも使われているとすると、上記のサンプル CSS を使用した場合には、すべてのコントロールのテキストが青色で表示されることになってしまいます。これらのコントロールの JavaScript ファイルには、最も外側の層で使用される baseClass 属性があります。この属性を使用すれば、CSS でそれぞれのコントロールを区別することが可能になります。Button の baseClass は dijitButton です。一方、他の 2 つのコントロールの baseClass は、それぞれ dijitComboButtondijitDropDownButton となっています。通常のボタンのテキストだけを青色で表示する場合の CSS は、リスト 9 のとおりです。

リスト 9. 通常のボタンのテキストを青色で表示するコード
.dijitButton .dijitButtonText
{
   color: blue;
}

Dojo スキンをベースとして使用する場合には、ベースとして指定したスキンの先頭行に .soria を追加すること、さらに可能な場合には .dijitButtonNode などのレベルも追加することをお薦めします。これは、同じ CSS クラスを 2 つの異なるファイルで使用する場合、対象としてはいない方のスキン、つまり修飾が追加されている方のスキンが使用される可能性があるからです。この計算がどのように行われるかは、CSS 仕様のセクション 6.4.3 に記載されています (「参考文献」を参照)。また、CSS の !important 修飾を追加してベースのスキンが強制的に使用されるようにすることもできます (CSS 仕様のセクション 6.4.2 に説明されています)。

さまざまなスキンとスタイルを使用すると、特定のクラスにどのスタイル定義を使用するのかを把握するのが難しくなる場合があります。そこで大いに活躍するのが、Firebug です。Web ページを表示した状態で Firebug コンソールを開くには、ブラウザー・ウィンドウの左下隅にあるアイコンをクリックしてください。Firebug コンソールの左側にある HTML タブに、画面に表示中の HTML コードが、クラス属性も含めて表示されます。HTML タグをクリックすると、このタグに影響する関連 CSS が右側の「スタイル (Style)」タブに表示されます。コード内で同じクラス属性が何度も定義されている場合、そのすべての定義と、そのなかでオーバーライドされた定義および使用されている定義が示されます。画面の特定領域のスタイル設定を確認するには、Firebug ツールバーの「調査 (Inspect)」をクリックしてから、画面上の領域/ウィジェットをクリックします。すると、その領域に関与する HTML コードまで移動し、対応する CSS が右側に表示されます。

図 1 は、Dijit Theme Tester で soria テーマの Create ボタンを調べている様子です。Firebug を見ると、(.dijitButtonNode だけでなく .soria .dijitButtonNode によっても修飾されている) soria.css に指定された余白スタイルによって、dijits.css に指定された余白スタイルが上書きされたことがわかります。

図 1. アプリケーションのデフォルト Dojo スタイル

Dojo のベース・ウィジェットを使用するなかで、私たちはいくつかの制約に突き当たりました。その 1 つは、特定のウィジェットに角丸を追加する機能です。Mozilla 固有の CSS スタイルを使用して角丸にすることは可能ですが、その場合、背景は一色にせざるを得なくなり、しかも Mozilla Firefox でしか機能しません。つまり、固定サイズの画像でない限り、コントロールの背景に角丸のグラデーション画像を使用できなくなるということです。これは、ボタンやタイトル・バーに可変のテキストが含まれている場合や、ボタンやタイトル・バーの幅と高さが固定されているのではなく、画面のサイズに応じてその表示サイズが決まったりする場合には、現実的でありません。

Dojo でも、dijit.form.Button などのウィジェットを使うことで、角丸を追加することは可能です。Dojo のテンプレートには、dijitLeft および dijitRight のクラス属性を持つ <div> 要素があります。これらの属性を使用すれば、左右それぞれの画像を角丸にすることができます。注意する点として、dijitRight 属性は 1.1.0 の初期バージョンでテンプレートから削除されていたため、上記に表示した Button のサンプル・テンプレートには示されていません。しかし、この点は修正されています。このようなクラスを見つけた場合、アプリケーションにとって修正が不可欠であれば、夜間ビルドによって修正されたファイルを取得することができます (「参考文献」に記載された Dojo ツールキットへのリンクを参照)。

図 2 に、Dojo soria テーマをそのまま使用した初期段階のアプリケーションの外観を示します。

図 2. アプリケーションのデフォルト Dojo スタイル
アプリケーションのデフォルト Dojo スタイル
アプリケーションのデフォルト Dojo スタイル

図 3 に、スタイル設定をカスタマイズした最終的なアプリケーションの外観を示します。

図 3. アプリケーションのカスタム Dojo スタイル

ナビゲーション支援 — パンくずリスト

パンくずリストは、ナビゲーションを追跡するために多くの Web サイトで使用されています。Dojo では、StackContainer のページをナビゲートできるようにする dijit.layout.StackContainer ウィジェットと併せて使用できる dijit.layout.StackController ウィジェットを用意しています。リスト 10 に、この 2 つのウィジェットの基本的な使用例を記載します。このコードは、ダウンロードして Dojo ソース・コードの <dojo_home>\dijit\tests\layout\ ディレクトリーから実行することができます。

リスト 10. dijit.layout.StackController ウィジェットと dijit.layout.StackContainer ウィジェットを併せて使用する方法
<div dojoType="dijit.layout.StackController" containerId="myStackContainer"></div>

<div id="myStackContainer" dojoType="dijit.layout.StackContainer"
    style="width: 90%; border: 2px solid; height: 100px;">
    <div id="page1" dojoType="dijit.layout.ContentPane"
  title="page 1">This is page 1.</div>
    <div id="page2" dojoType="dijit.layout.ContentPane"
  title="page 2">This is page 2.</div>
    <div id="page3" dojoType="dijit.layout.ContentPane"
  title="page 3">This is page 3.</div>
</div>

Dojo の soria スタイルシートを使用した場合、このコードは図 4 のように表示されます。

図 4. soria スタイルシートを使用した StackContainer アプリケーション
StackContainer application using             soria stylesheet
StackContainer application using soria stylesheet

StackController の各ボタンをクリックすると、対応するページが表示されます。一方、典型的なパンくずリストの振る舞いでは、ドリルダウンするに従ってページが追加され、ページ 1 をクリックすると最初のページに戻り、その他すべてのページがパンくずリスト (および StackContainer) から削除されます。このような振る舞いをお望みの場合には、カスタム・コードが必要になります。

出発点とするコードはリスト 10 と同じですが、StackContainer には最初の静的ページが含まれていない状態になっています (リスト 11 を参照)。

リスト 11. 初期の静的ページが含まれないコード
<div dojoType="dijit.layout.StackController" containerId="myStackContainer">
</div>

<div id="myStackContainer" dojoType="dijit.layout.StackContainer"
    style="width: 90%; border: 2px solid; height: 100px;">
</div>

ページのドリルダウン操作をシミュレートするため、StackContainer に動的にページを追加するボタンを追加します。

リスト 12. 動的にページを追加するボタンの追加
<button dojoType="dijit.form.Button"
    showLabel="true"
    label="Add Page"
    onClick="loadPage">
</button>

loadPage コードは、dijit.layout.ContentPane を作成して myStackContainer に追加します (リスト 13 を参照)。

リスト 13. dijit.layout.Content.Pane の作成
var nPages = 0;
  function loadPage()
  {
    nPages = nPages + 1;
    var container = dijit.byId('myStackContainer');
    if( container )
    {
      var pageid = "page" + nPages;
      add(container,"Page " + nPages, pageid);
      container.selectChild(pageid);
    }
  }

  function add(parent,name,id)
  {
    var node = document.createElement("div");
    var child = new dijit.layout.ContentPane
      ( {title: name, id: id },node );
    parent.addChild(child);

    //add content to the new page
    dojo.byId(id).innerHTML = name;
  }

以上のコードを追加した初期画面は、図 5 のようになります。

図 5. soria スタイルシートを使用した変更後のアプリケーション — 初期画面
soria スタイルシートを使用した変更後のアプリケーション 初期画面
soria スタイルシートを使用した変更後のアプリケーション 初期画面

Add Page ボタンを 2 回クリックすると、画面は図 6 のようになります。

図 6. soria スタイルシートを使用した変更後のアプリケーション — 2 ページが追加された状態
soria スタイルシートを使用した変更後のアプリケーション 2 ページが追加された状態
soria スタイルシートを使用した変更後のアプリケーション 2 ページが追加された状態

Page 1 をクリックしても、Page 2 は StackController にそのまま残ります。Stack Controller でボタンがクリックされたときに、そのボタンに対応するページがまだ表示されていなければ、StackContainer に固有の selectChild イベントが起動されます。ユーザーがパンくずリストの前のページに戻ることにしたときに、Stack Controller を操作してユーザーにそのページを表示できるようにするには、このイベントを購読する必要があります。それを行うコードが、リスト 14 です。ここでは、このアクションを処理するために selectedPage という名前のメソッドを実装します。

リスト 14. selectedPage メソッドの実装
dojo.subscribe("myStackContainer-selectChild","","selectedPage");

selectedPage メソッドは、removeDownstream という名前のヘルパー・メソッドを呼び出します。removeDownstream はクリックされたページのインデックスを取得し、その特定のインデックス以降にあるすべてのページを削除します (リスト 15 を参照)。

リスト 15. removeDownstream メソッドの使用
function selectedPage(page)
 {
    removeDownstream(page.id) ;
 }

function removeDownstream( pageid )
{
    var widget = dijit.byId('myStackContainer');
    if(widget)
    {
      var children = widget.getChildren();
      var index = dojo.indexOf(children, dijit.byId(pageid));
        //get index of page that was selected from the breadcrumb trail
      index = index+1; //start removing from the page to the right
      while( children.length > index )
      {
        widget.removeChild(children[ index ]);
        index = index + 1;
       }
    }
}

このコードを組み込んだ状態でパンくずリスト内の前のページに戻ると、後続のすべてのページがパンくずリストおよび StackContainer ウィジェットから削除されます (この振る舞いは、このコードをダウンロードして実行し、Firebug で HTML ソースを調べることによって簡単に検証することができます)。

典型的なパンくずリストにより近い外観にするには、CSS と DOM のスタイル操作を使ってパンくずリストのノードのスタイルを設定します。スタイル設定は、完全なサンプル・コード (ダウンロード可能) に組み込まれていますが、ここでは詳しく説明しません。以下に、最終的なサンプルの外観と動作を説明します。

Add Page ボタンを 4 回クリックして 4 つのページを追加すると、パンくずリストは図 7 のような表示になります。

図 7. パンくずリストを使用した変更後のアプリケーション — 4 ページが追加された状態
パンくずリストを使用した変更後のアプリケーション 4 ページが追加された状態
パンくずリストを使用した変更後のアプリケーション 4 ページが追加された状態

Page 2 をクリックした場合に表示される結果は、図 8 のとおりです。

図 8. パンくずリストを使用した変更後のアプリケーション — ページ 2 に戻った場合
パンくずリストを使用した変更後のアプリケーション ページ 2 に戻った場合
パンくずリストを使用した変更後のアプリケーション ページ 2 に戻った場合

ツリー — 有効/無効に設定されたノード

Dojo の dijit ライブラリーには、基本的なツリー機能を備えた Tree ウィジェットが含まれています。このツリーには各ノードを展開および折り畳むためのメソッドがありますが、私たちが必要としたのは、ノードの無効化機能も提供するツリーです。ノードを無効に設定するにはいくつかの方法があります。例えば、まったく新しいウィジェットを一から作成するという方法もあれば、Dojo の Tree ウィジェットをベースに独自のウィジェットを作成するという方法もあります。あるいは Dojo が提供する機能を利用してこのタスクを実現することもできます。ここでは、Dojo を利用する場合の手順を説明します。

Dojo ツリーの各レベルは、アイコンとラベルで構成されます。Dojo では、Tree のタグにコールバック・メソッドを指定して、ツリー内の各項目に使用しなければならないラベルとアイコンのスタイル・クラスを取得できるようになっています。ここではこの仕組みを利用して無効なノードのスタイルを設定し、無効化されたノードとして表示することにします。このサンプルで無効にするのは、リーフ以外のすべてのノードです。リーフでないノードは、タスクの実行対象の項目を分類するためだけに使用するのが一般的だからです。

まず始めに、リスト 16 に示す CSS スタイルを定義します。

リスト 16. CSS スタイルの定義
.enabled
 {
        color: black;
        cursor: pointer;
 }

 .disabled
 {
        color:gray;
        cursor: not-allowed;
       background-color: transparent !important;
 }

ノードをクリックすると、ノードには新しいクラス属性、dijitTreeLabelFocused が追加されます。無効化のスタイルには !important を使用することで、dijitTreeLabelFocused によって設定された背景色に透明な背景色が確実に重ねられるようにします。このようにして、ノードをクリックしてもそれが選択されていないように見せるわけです。

ラベル・スタイルのコールバック・メソッドは、Tree ウィジェットによって渡される 2 つのパラメーター (クリックされた項目と、ツリー・ノードが現在開かれているかどうかを示すブール値パラメーター) を取ります。このメソッドは、リスト 17 のようになります。

リスト 17. プロトタイプのコールバック・メソッド
function getLabelClassForMyTree(
            /*dojo.data.Item*/ item, /*Boolean*/ opened)
 {
        if( item && item.children )
                  return "disabled";

        return "enabled";
 }

このメソッドを利用するには、ツリー・ウィジェット・タグの getLabelClass 属性を指定する必要があります (リスト 18 を参照)。

リスト 18. getLabelClass 属性の指定
<div dojoType="dijit.Tree" id="myTree" model="model"
        onClick="onSelectItem"
        getIconClass="getIconClassForMyTree"
        getLabelClass="getLabelClassForMyTree">
        </div>

このスタイル設定は、ラベル自体のスタイルにのみ適用されることに注意してください。つまり、アイコンやラベル右側のスペースにマウスを重ねても、無効化のカーソル・スタイルは表示されません。カスタム画像でアイコンをスタイル設定することで、リーフ以外のノードにマウスを重ねるとアイコンが無効になっているように表示するには、リスト 19 に記載するコールバック・メソッドを使用することができます。その上で、この関数をツリー・ウィジェット・タグの getIconClass 属性に指定します (リスト 18 を参照)。

リスト 19. カスタム画像でのアイコンのスタイル設定
function getIconClassForMyTree(
/*dojo.data.Item*/ item, /*Boolean*/ opened)
     {
          var style = "";
          if( item )
          {
               if( item.children )
               {
                    //add icon image style
          style = opened ? "customFolderOpenedIcon" :
"customFolderClosedIcon";

                    //add disabled style
                    style = style + " disabled";
                     }
                    else
{
                          //add icon image styling and enabled styling
                    style = "noteIcon enabled";
                }
          }
          return style;
}

しかし、行の残りについてはまだ、マウスを重ねても無効になっているようには表示されません。Dojo はアイコンのクラスとラベルにだけコールバックを行うため、行の残りの外観を無効にするとなるとそう簡単にはいきません。オプションの 1 つは、ツリーが作成された後にすべてのノードを繰り返し処理し、ラベルとアイコンをカプセル化する行に無効化または有効化のスタイルを追加するという方法です。該当する DOM ノードには、各ツリー・ノードの rowNode 属性を使用してアクセスすることができます。

無効化ノードの関数を無効にするには、無効化されたノードに対して onClick を無効にして戻ればよいだけです。リスト 20 のメソッドを使用すれば、無効化されたノードがクリックされた場合には単に戻るという方法で、onClick イベントを無視することができます。

リスト 20. onClick の無効化
function onSelectItem(item) {
       if(item.children) //disabled node, ignore click event
           return;

       if(item) {
              // Display basic attribute values
              dojo.byId('uLabel').value = item ?
                  store.getLabel(item) : "";
       }
}

リスト 20 のメソッドをリスト 21 のように変更すれば、有効なノードが選択状態になった後、無効なノードがクリックされても、選択されたノードがそのスタイルを維持することができます。

リスト 21. 選択されたノードのスタイルを維持する方法
function onSelectItem(item,node){

        if(item.children)
        {
            if(previouslySelectedNode)
                  //keep currently selected node highlighted
dojo.addClass(previouslySelectedNode,"dijitTreeLabelFocused");
            return;
        }

        if(item){
            if(previouslySelectedNode)
                //in case we set that ourself, remove it
dojo.removeClass(previouslySelectedNode,"dijitTreeLabelFocused");

            //keep track of enabled selected node
            previouslySelectedNode = node.labelNode;

            // Display basic attribute values
            dojo.byId('uLabel').value = item ? store.getLabel(item) : "";
        }
        }

上記のサンプルの動作を確認するには、test_Tree_disable_style.html を <dojo_home>/dijit/tests/ ディレクトリーにダウンロードして、ファイルをブラウザーで実行してください。最初のファイルは、コールバックのみを使用してノードを無効にする方法を説明し、2 番目のファイルは rowNode を使用してノードが無効にされているように表示する方法を説明します。

行ごとに異なるオプションを使用するグリッド・エディター

最近の大抵の Web 2.0 技術では、グリッドと呼ばれる複合テーブル用のウィジェットを用意しています。これらのグリッド・テーブルには、HTML SELECT と同じような列の値を選択する機能が組み込まれています。しかし、この列選択機能には、列は静的であるという制約、そしてテーブル全体に 1 つのオプション・セットしかないという制約があります (例えば、1 列目のすべての行で、オプションは同じになります)。図 9 に、単純な Dojo グリッド・アプリケーションを示します。このアプリケーションでは、1 列目のオプションはすべて各行 (normal、note および important) で共通しています。

図 9. Dojo グリッド・エディター Select — 標準
Dojo グリッド・エディター Select 標準
Dojo グリッド・エディター Select 標準

私たちに必要だったのは、グリッド・テーブルの各行それぞれのオプションを変えることのできる動的オプションです。そのため、いくつかのカスタマイズが必要になりました。この問題を解決するには何通りかの方法があります。必要最小限の方法として、グリッド Select エディターのフォーマッターをオーバーライドし、選択した行のオプション情報を返すことはできます。しかしそうしたとしても、グリッドのモデル内にある列のオプションと値は何の意味も持ちません。グリッドの行とグリッド外部のあらゆるタイプのモデル・データとの関連付けは、慎重に行わなければなりません。グリッド内の行の順序は (例えば、ソート・アクションなどによって) 常に変更される可能性があるからです。実際のグリッド・モデルの外部に拡張モデル情報を維持する場合、グリッド・モデル内で変更した行が、グリッド外部のデータに含まれると想定していた行とは異なる可能性があります。このような不一致を避ける方法として最善であると私たちが考えるのは、表示されない追加の情報 (行のオプションや値など) をグリッド・モデル自体のなかに保持することです。こうすれば、フォーマッターのオーバーライドが、該当する拡張モデル情報を返すことができます。リスト 22 からリスト 26 にスニペットを記載します。

全体として、これを実現するステップには以下の 3 つの基本ステップがあります。

  1. グリッドのデータ・モデルを拡張して行ごとのオプション情報を追加する
  2. カスタム・グリッド・エディターを作成して、format メソッドを特殊化する
  3. カスタム・セレクターの使用をグリッド・レイアウトに組み込む

グリッドのデータ・モデルを拡張して行ごとのオプション情報を追加する

リスト 22 に記載するのは、行ごとのオプションを変えるための変更をまだ行っていない状態のグリッド・データです。

リスト 22. 変更前のグリッド・データ
var data = [
    ["normal",   "message-1","Priority-1"],
    ["note",     "message-2","Priority-2"],
    ["important","message-3","Priority-3"]
 ];

リスト 23 に記載する変更後のグリッド・データでは、データ配列の列 4 に行ごとに異なるオプションを使用しています。

リスト 23. 行ごとに異なるオプションを使用するための変更
var data = [
    ["normal-1",   "message-1","Priority-1",["normal-1","note-1","important-1"]],
     "note-2",     "message-2","Priority-2",["normal-2","note-2","important-2"] ],
    ["important-3","message-3","Priority-3",["normal-3","note-3","important-3"] ]
];

択された行のオプションを返すカスタム・グリッド選択エディターを作成する

このステップでは、dojox.grid.editors.Select のサブクラスを作成し、format メソッドを特殊化します。エディターのオプションを現行の行のオプションに設定し、この情報の実際のフォーマット設定はその親に行わせます。これにより、各行に異なるオプションが設定されることになります。このサンプルでは、オプションと値は両方同じだということに注意してください。グリッド・モデル・データで値に別の列を追加すれば、オプションと値を区別することができます。この方法を説明するため、リスト 24 のサンプルでは新しいエディター MySelect を作成しています。

リスト 24. オプションと値を区別する方法
dojo.declare("com.ibm.editor.MySelect", [dojox.grid.editors.Select], {
     format: function(inDatum, inRowIndex){
           var row = this.cell.grid.model.data[inRowIndex];
            this.options = this.values = row[OPTION_INDEX];   // could have diff values
            return this.inherited("format",arguments);        // return HTML select stmt
      },
});

カスタム・セレクターの使用をグリッド・レイアウトに組み込む

リスト 25 のサンプルに、標準 dojo グリッド・エディターを使用したグリッド・レイアウトを記載します。オプションと値はテーブル内のすべての行で同じなので、グリッド・レイアウトには両方とも含まれていることに注意してください。

リスト 25. 標準 dojo グリッド・エディターを使用したグリッド・レイアウト
gridLayout = [{
         type: 'dojox.GridRowView', width: '20px'
         },{
        defaultCell: { width: 8, editor: dojox.grid.editors.Input, styles: 'text-
        align: right;' },
        rows: [[
                {name: 'Source Schema: Current',styles: '',    width: '40%',    editor:
               dojox.grid.editors.Select, options: ["normal", "note", "important"],
               values: [0, 1, 2], formatter: function(inDatum) { return
               this.options[inDatum]} },
               {name: 'Mapping',    styles: '',    width: '20%'},
               {name: 'Target Schema: ',    styles: '',    width: '40%'}
        ]]
}];

リスト 26 のサンプルに、グリッド・レイアウトがカスタム・グリッド・エディターを使用するための方法を示します。この場合、すべての行のオプションは異なるため、テーブル全体のオプションを定義する必要はありません。

リスト 26. カスタム・グリッド・エディターを使用したグリッド・レイアウト
gridLayout = [{
      type: 'dojox.GridRowView', width: '20px'
      },{
      defaultCell: { width: 8, editor: dojox.grid.editors.Input, styles:
                               'text-align: right;' },
      rows: [[
            {name: 'Source Schema: Current',styles: '', width: '40%',
              editor: com.ibm.editor.MySelect }
            },
            {name: 'Mapping',	styles: '',	width: '20%'},
            {name: 'Target Schema: ',	styles: '',	width: '40%'}

      ]]
}];

グリッド・テーブル選択エディターで行ごとに異なるオプションを設定するために Dojo ウィジェットをカスタマイズした結果、図 10 のような表示になりました。最後の行の選択オプションとして表示されている normal-3、note-3、important-3 は、他の行で選択されているオプション normal-1、note-2 とは異なることに注目してください。

図 10. Dojo グリッド・エディター Select — カスタマイズ後
Dojo グリッド・エディター Select カスタマイズ後
Dojo グリッド・エディター Select カスタマイズ後

Dojox グリッドのサンプル <dojo_home>/dojox/grid/tests/test_edit.html は、行ごとに異なるオプションをサポートするように変更されています。これらのサンプルの動作を確認するには、test_edit_simple.html および test_edit_diff_options.html を <dojo_home>/dojox/grid/tests ディレクトリーにダウンロードして、ファイルをブラウザーで実行してください。最初のファイルでは、非常に単純なアプリケーションの中で、すべての行に同じオプションを使用した標準グリッド・テーブルを操作する方法を説明しています。2 番目のファイルでは、カスタム・グリッド・エディター Select を使用した場合を説明しています。

ツリー — スタイルの指定による編集

このアプリケーションでは、ユーザーがグラフィカル・ツリーで最小限の編集を行うことができます。具体的には、ツリー内のノードと子ノード (オプション) の削除 (ドロップ)、ノードのラベル名の変更、ノードでの編集内容の取り消し/クリアです。ノードを編集するには、以下の 2 つの表示に関するステップがあります。

  1. 選択したノードに編集アクションに応じたスタイルを定義し、適用します (例えば、色の変更、テキストの取り消し線付加など)。
  2. 一部の編集アクションでは、ノードを変更します (例えば、ラベルの変更、ノードの折り畳みなど)。

これらの編集アクションのために、通常のツリーを作成しました。その方法は、HTML テンプレートにストア、モデル (非表示)、ツリーを作成するというものです。

リスト 27. ツリーの作成
<div dojoType="dijit.Tree"
        id="current_tree_${id}"
        class="container"
        model="current_tree_model_${id}"
        labelAttr="name"
        childrenAttr="children, items"
        dojoAttachEvent="onClick:_onClickSelect"
        getLabel="ourCustomLabel"
        getLabelClass="getOurLabelClass"
        getIconClass="getOurIconClass">
</div>

ツリーには、右クリックで編集オプションを表示するコンテキスト・メニューを追加しました。リスト 28 の connect が、このメニューをツリーに追加します。

リスト 28. 右クリックによるコンテキスト・メニューの追加
<script type="dojo/connect">
        var menu = dijit.byId("edit_tree_menu_${id}");
        menu.bindDomNode(this.domNode);
</script>

注: このサンプルでは、ユーザーがマウスの左ボタンを使って対象のノードを選択することを前提としています。

HTML テンプレートでのメニューの定義は、リスト 29 のようになります。

リスト 29. メニューの定義
<ul dojoType="dijit.Menu"
id="edit_tree_menu_${id}"
style="display: none;"
iconClass="dijitMenuItemIcon">

        <li id="edit_clear_menu_${id}"
        dojoType="dijit.MenuItem"
        dojoAttachEvent="onClick:_onClickClear"
        iconClass="dijitEditorIcon dijitEditorIconUndo"
        disabled="true">
        Clear Edit</li>

        <li dojoType="dijit.MenuItem"
        iconClass="dijitEditorIcon dijitEditorIconWikiword"
        disabled="true" >
        Create Expression</li>

        <li id="edit_drop_menu_${id}"
        dojoType="dijit.MenuItem"
        dojoAttachEvent="onClick:_onClickDrop"
        iconClass="dijitEditorIcon dijitEditorIconDelete"
        disabled="false" >
        Drop</li>

        <li dojoType="dijit.MenuItem"
        dojoAttachEvent="onClick:_onClickRename"
        iconClass="dijitEditorIcon dijitEditorIconCreateLink">
        Rename</li>

        <li id="edit_menu_remove_${id}"
        dojoType="dijit.MenuItem"
        dojoAttachEvent="onClick:_onClickRemove"
        iconClass="dijitEditorIcon dijitEditorIconCut">
        Remove</li>

</ul>

このツリーにはさらに、編集可能ノードを対象に、Dojo フォーラムで見つけたトリックを追加しています。

リスト 30. オーバーライドによるキー押下の無効化
<script type="dojo/method" event="_onKeyPress">
        //disable keypress via override, so we can use inline editor on nodes
</script>

最後に、選択されたオプションに基づいて、スタイルを適用し、可能な場合にはノードを変更する、編集アクションに対する適切なハンドラーを作成しました。

以下のリスト 31 に、remove ノード・ハンドラーのスニペットを記載します (このハンドラーが呼び出される前に、ユーザーがノードを選択します。ノードの選択によって、this.item が設定されます)。このハンドラーによって発生する可視のアクションは、スタイルが適用されてノードが削除されたことを示し (赤い取り消し線)、このノードの取り消しメニュー項目が使用可能になるというものです。

リスト 31. remove ノードのスニペット
/**
* User clicked on remove button or right context menu
* @param {Object} e
*/
_onClickRemove: function (/*Event*/ e) {
        . . .
        this.store.setValue(this.item,"edit","editRemove"); //add remove style
        dijit.byId("edit_clear_menu_"+this.id).setDisabled(false);//enable undo
        // process remove, e.g. report to server . . .
},

以下のリスト 32 に、remove ツリー・ノードのスタイル定義を記載します。

リスト 32. remove ツリー・ノードのスタイル定義
#edit .editRemove
{
        color: red;
        text-decoration: line-through;
}

リスト 33 は、rename ノード・ハンドラーのスニペットです。このハンドラーによって、ユーザーがツリー内のノードのラベル名を変更することができます。

リスト 33. rename ノード・ハンドラーのスニペット
/**
 * User clicked on rename button or right context menu
 * Bring up editor for tree node name
 * @param {Object} e
 */
    _onClickRename: function (/*Event*/ e) {
        . . .
        this.store.setValue(this.item,"edit","editRename"); //add rename style

        var labelNode = tree._itemNodeMap[ this.item.ID ].labelNode;
        var txt = document.createElement('span');
        txt.innerHTML = labelNode.innerHTML;
        labelNode.innerHTML = "";
        labelNode.appendChild(txt);

        var editor = new dijit.InlineEditBox({
            autoSave: true, // false=save/cancel button shown in html
            onChange: function(value) {
                this.setDisabled(true); // done, disable editing
                // process rename, e.g. report to server . . .
            },
            renderAsHtml: true,
            width: "150px"
        }, txt);
        editor.setDisabled(false); //enable editing
        editor._edit();

        dijit.byId("edit_clear_menu_"+this.id).setDisabled(false);//enable undo
        . . .
},

rename ツリー・ノードのスタイル定義は、リスト 34 のとおりです。

リスト 34. rename ツリー・ノード・スタイル
#edit .editRename
{
        color: blue;
}

ノードの名前変更アクションの場合、ツリー・ノード・エディターは図 11 のように表示されます。

図 11. ツリー・ノードの編集 — 名前変更
ツリー・ノードの編集 名前変更

最終的な結果は、図 12 のとおりです。このように、右クリックによるコンテキスト・メニューには、選択可能なさまざまな編集オプションが表示されます。削除すなわちドロップされたツリー・ノードには赤い取り消し線のスタイルが設定され、名前が変更されたツリー・ノードは青色で表示されます。

図 12. 右クリックによるコンテキスト・ツリー・メニューおよびスタイル設定された編集後のノード
右クリックによるコンテキスト・ツリー・メニューおよびスタイル設定された編集後のノード

ツリー — 右クリックによるコンテキスト・メニューと右クリックによる選択

前のセクションでは、選択したノードを変数に保管し、その変数を右クリックによるコンテキスト・メニューでオプションが選択されたときに使用できるようにするためには、ノードを左クリックする必要がありました。このようにしたのは、右クリックによるコンテキスト・メニューは、ツリーの各ノードにではなく、1 つの単位としてのツリー全体にバインドされていたからです。右クリックされたノードに応じた特定の振る舞いにするには、メニューの _openMyself メソッドに接続するという方法があります (リスト 35 を参照)。

リスト 35. _openMyself メソッドへの接続
<div dojoType="dijit.Tree" … >

        <script type="dojo/connect">
            var menu = dijit.byId("tree_menu");

            dojo.connect(menu, "_openMyself", this, function(e){

                // get the tree node that was the source of this open event
                var tn = dijit.getEnclosingWidget(e.target);

                // if this tree node does not have any children,
        // disable all of the menu items
        // note: these lines are not related to the above section, just
        // shown to illustrate how menu items would be disabled
        // depending on which node was clicked.
                menu.getChildren().forEach(
            function(i){
                i.setDisabled(!tn.item.children);
            });

                // IMPLEMENT CUSTOM MENU BEHAVIOR HERE
            });
        </script>
</div>

tn 変数は、メニュー・オプションがクリックされた後にアクセスできるグローバル変数として保管することができます。このようにすると、ユーザーはメニュー・アクションを適用するノードを最初に左クリックしなくても済むようになります。

よくある失敗

このセクションでは、以下に挙げる、よくありがちな失敗について説明します。

  • 複数のグローバル JavaScript メソッドに同じ名前を設定すること。この場合、エラーがレポートされず、どのメソッドが呼び出されるのかがわかりません。
  • オブジェクトを十分に分離していないため、使用できるグローバル関数があり過ぎること。この場合、コードの保守が難しくなるだけでなく、上述した一般的な失敗の原因になる可能性もあります。
  • 過剰なログ/トレース、あるいはログ・メッセージの不十分なフィルタリングにより、ログに記録される情報が過多になること。
  • 非効率的なエラー処理によってデバッグが困難になること。例外処理を改善し、エラーの過程を十分に考慮する必要があります。
  • オブジェクト属性のスコープを誤って使用すること (グローバルとローカルの違い)。
  • 必要なところでコールバックに dojo.hitch を使用していないこと。コールバックが正しいオブジェクト・コンテキストで実行されていないことを発見するまでに時間がかかる可能性があります (例えば、オブジェクト・インスタンス変数の値が誤っているなど)。

Dojo アプリケーションのテスト

ローカルおよびリモート

Web 2.0 アプリケーションでは、その情報を取得する手段として RESTful なサービスを使用します。REST とは REpresentational State Transfer の頭辞語で、これは World Wide Web がベースとするアーキテクチャー・モデルです。REST の原則には、リソースを中心とした手法、すべての関連リソースに URI でアクセス可能なこと、HTTP の GET、POST、PUT、DELETE を使用した統一アクセスなどがあります。アプリケーションのテストは、接続されていないローカル・モードで実行できるようにしたかったため、RESTful なサービスの結果をテスト・ファイルに保存し、特定の REST 呼び出しの URL を取得する抽象化メソッドを作成しました。

自動検出および切り替えの例

この抽象化では、document.location.protocol の JavaScript 値を使用してアクセスがローカルまたはリモートのどちらであるかを判別し、適切な URL を返します。その手段として、サーバー URI と同様のディレクトリー構造にローカル・テスト・ファイルを配置しました。例えば、サーバー http://<server>:<port> の URI が /catalog/types だとすると、この URI をローカル・ベースのテスト・ディレクトリー <local-test-base-dir>/myui/catalog/types に配置します。この URI は、アクセスがローカルか、リモートかによってベースの部分だけが変更されます。構成オブジェクトの BASE_URL 属性は、以下のように設定しました。

config.BASE_URL = (document.location.protocol=="file:") ? "data" : "..";

まとめ

概して、Dojo ツールキットに用意された豊富なサンプル、Dojo を中心としたコミュニティー、そしてインターネット上の大量のJavaScript 情報などを利用することにより、Dojo 開発を開始する際の学習曲線は最短になることがわかりました。ただし Java 開発者としては、IDE の強力なサポートや優れた API ドキュメントが欲しかったところです。また、強力な型付け、Web ブラウザーの違いによって異なる実行時の振る舞い、JavaScript 開発でのコンパイル時チェックも欠けています。カスタマイズの方法を学ぶのは、時には困難で、大抵は試行錯誤のプロセスとなりますが、いったん学んだプロセスは繰り返すことができます。私たちが作成したプロトタイプは最終的に、Ajax対応の Web アプリケーションに期待されるあらゆるパフォーマンスの利点を実現する本格的なアプリケーションになりました。


ダウンロード可能なリソース


関連トピック

  • Dojo のメイン・サイトで、他の Dojo 開発者たちによるヘルプ情報を見つけてください。
  • Java 開発者にとっての Dojo の概念」(developerWorks、2008年10月) を読んでください。Java コードから Dojo へ移行するための橋渡しをするこの記事によって、ツールキットをすぐに理解してアプリケーション開発で使えるようになります。
  • JavaScript で MVC デザイン・パターンを使用する詳しい方法を学んでください。この記事のサンプルでは下位レベルの Dojo を使用していますが、それでもマイナーな変更には適用できます。
  • CSS2 仕様を参照してください。
  • Dojo ツールキットをダウンロードしてください。
  • この記事のプロトタイプには Firebug プラグインが使用されています。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=367269
ArticleTitle=カスタム Dojo アプリケーションを作成する
publish-date=12092008