XPagesは、Lotus Notes/Domino 8.5(以下、Lotus NotesはNotes、Lotus DominoはDominoと表記)から登場した、Notes/Domino上で動作するWebテクノロジーを利用したアプリケーションを開発するための技術です。その特徴の1つとして挙げられるのは、リッチなユーザー・インターフェースやAJAXによるタイプアヘッド、画面の部分更新などの機能をもつWeb2.0スタイルのアプリケーションを簡単に開発できる点です。こうしたWeb2.0スタイルのアプリケーションを実現するにあたって、XPagesではオープンソースJavaScriptライブラリであるDojo Toolkitが採用されており、XPages内部の実装でも利用されています。そのため、Dominoサーバーのインストール時には、Dojo Toolkitがデフォルトでインストールされるようになっています。カスタムインストールの場合は、XPages機能を利用するためには図1のようにDojoとXPagesを選択し、XPagesとともにDojo Toolkitも必ずインストールする必要があります。
図1. Dominoサーバーのカスタムインストール画面: XPagesとDojoを選択してインストール
こうしてインストールされたDojo Toolkitのブートストラップとなるスクリプトのdojo.jsには、リスト1に示したURLを使ってアクセスすることができます。先にも述べたように、Dojo ToolkitはXPages内部でも利用されているため、XPageでページを作成すると、明示的な指定をしなくてもこのdojo.jsがページにロードされるようになっています(図2)。
リスト1. Dominoサーバーのdojo.jsファイルのURL
// バージョン8.5の場合 http://<Dominoサーバーのホスト名>/domjs/dojo-1.1.1/dojo/dojo.js // バージョン8.5.1の場合 http://<Dominoサーバーのホスト名>/domjs/dojo-1.3.2/dojo/dojo.js |
図2. XPagesで作成したページのHTMLソース: dojo.jsがデフォルトで読み込まれている
このように、Dojo ToolkitはXPageで作成したページに自動的に読み込まれますが、XPagesが提供する標準コントロールや基本機能を利用してアプリケーションを開発する限りでは、Dojo Toolkitの存在はXPagesの中に完全に隠蔽されているため、開発者がDojo Toolkitの存在を意識する必要はありません。あくまでXPagesの範囲で開発を行えばよく、その結果として出来上がったページの中で内部的にDojo Toolkitが使われます。
Dojo Toolkitは非常に沢山の機能を提供しているため、Dojo Toolkitが提供している機能であっても、XPagesの標準機能としては提供されていないものも数多くあり、それらの機能を積極的に活用することも可能です。特に、Dojo Toolkitが提供するユーザー・インターフェースのコンポーネントであるDojoウィジェットは、種類が非常に豊富ですが、XPagesの標準コントロールの中で利用されているのは日時ピッカーやリッチテキストエディタなどに限られており、ほとんどのDojoウィジェットがXPagesの標準コントロールとしては提供されていません。本稿ではこうしたXPagesの標準コントロールとして提供されていないDojoウィジェットに焦点を当て、XPageの中で利用する方法について紹介していきます。
なお本稿ではXPagesおよびDojo Toolkitについての解説は行いませんが、詳しく知りたい方は本稿の最後にある参考文献リストに挙げたXPagesとDojo Toolkitの関連記事を参考にしてください。
XPagesでDojo Toolkitを利用するにあたっての注意点
XPagesでDojo Toolkitを利用するにあたって、注意すべき点が1つあります。それは、Dojo Toolkitのバージョンです。リスト1で示したdojo.jsのURLからも分かるように、Notes/Dominoのバージョンによって、インストールされるDojo Toolkitのバージョンが異なります。具体的には、以下の表1に示したバージョンのDojo Toolkitがそれぞれインストールされています。
表1. 各バージョンのDominoサーバーにインストールされているDojo Toolkitのバージョン
| Dominoバージョン8.5 | Dominoバージョン8.5.1 | |
|---|---|---|
| Dojo Toolkitのバージョン | 1.1.1 | 1.3.2 |
先にも述べたように、XPagesが提供する標準コントロールや基本機能を使用しているだけであれば、開発者はDojo Toolkitの存在を意識することがないため、Dojo Toolkitのバージョンも意識する必要はありません。しかし、これから紹介するDojoウィジェットをXPagesで使用する場合や、Dojo ToolkitのAPIをクライアントサイドJavaScriptから直接呼び出す場合には、提供されているDojoウィジェットやAPIなどがDojo Toolkitのバージョンによって異なるため、バージョンを意識しておく必要があります。また、Dominoサーバーのバージョンアップを行う場合には、それに伴ってDojo Toolkitのバージョンも上がる可能性があるため、アプリケーションの中で使用しているDojoウィジェットやAPIの互換性について事前にきちんと確認することが重要です。
Dojoウィジェットは、Dojo Toolkitが提供するユーザー・インターフェース(以下、UI)のコンポーネントです。ボタン(Button)、コンボボックス(ComboBox)といった基本的なウィジェットから、グラフを表示するChartingウィジェット、テーブル形式のデータ表示・編集機能を提供するGridウィジェット、ツリー形式のデータ表示を行うTreeウィジェットといった高機能なウィジェットまで、数多く提供されています(図3)。
図3. Dojoウィジェットの例
XPagesでのDojoウィジェットの利用法を紹介する前に、比較のために通常のHTMLページの中でDojoウィジェットを利用する方法を、図4のCalendarウィジェットの例で紹介します。この例では、Calendarウィジェットと共に入力フィールドを配置し、Calendarウィジェットの日付をクリックした際に、その日付が入力フィールドにセットされるようにします。
図4. Calendarウィジェットの例
Calendarウィジェットに限らず、一般的にDojoウィジェットをWebページの中で利用する方法は2つあります。1つはHTMLマークアップの中で使用するDojoウィジェットを静的に宣言する方法、もう1つはJavaScriptのコードによって動的に生成する方法です。ここでは前者のHTMLマークアップで宣言する方法を使って実装します。図4のCalendarウィジェットのHTMLソースは以下のリスト2のようになります。
リスト2. Calendarウィジェットを利用するHTMLのソース例
<html> <head> <title>Calendarウィジェットサンプル</title> <link rel="stylesheet" type="text/css" href="/domjs/dojo-1.3.2/dojo/resources/dojo.css"> <link rel="stylesheet" type="text/css" href="/domjs/dojo-1.3.2/dijit/themes/tundra/tundra.css"> <!-- b --> |-------10--------20--------30--------40--------50--------60--------70--------80--------9| |-------- XML error: The previous line is longer than the max of 90 characters ---------| <script type="text/javascript" src="/domjs/dojo-1.3.2/dojo/dojo.js" djConfig="parseOnLoad: true"></script> <!-- a --> <script type="text/javascript"> dojo.require("dijit._Calendar"); // <!-- c --> dojo.addOnLoad(function(){ // <!-- f --> dojo.connect(dijit.byId("calendar"), "onValueSelected", function(date) { var formattedDate = dojo.date.locale.format(date, {formatLength: "medium",selector: "date"}); |-------10--------20--------30--------40--------50--------60--------70--------80--------9| |-------- XML error: The previous line is longer than the max of 90 characters ---------| document.getElementById("selectedDate").value = formattedDate; }); }); </script> </head> <body class="tundra"> <div> <!-- d,e --> <div id="calendar" dojoType="dijit._Calendar" dayWidth="narrow" style="width:200px"/> |-------10--------20--------30--------40--------50--------60--------70--------80--------9| |-------- XML error: The previous line is longer than the max of 90 characters ---------| </div> <div><input id="selectedDate" type="text"/></div> </body> </html> |
ポイントは以下の通りです。(見出しのアルファベットは、リスト2のコード内の<!-- -->で示した部分にそれぞれ対応しています)
- <script>タグでdojo.jsをロードします。このとき、HTMLマークアップの中でDojoウィジェットを宣言する場合には、djConfig=”parseOnLoad:true”という属性をつけておくと、dojoのロード時にHTMLマークアップがパースされて、指定したDojoウィジェットに変換されます。
- <link>タグでDojoウィジェットのテーマとなるCSSファイルを読み込みます。ここではtundraテーマを使用するためにtundra.cssを読み込み、bodyのclassにtundraを指定しています。
- <script>タグの中のJavaScriptで、必要なDojoウィジェットのクラスをdojo.require関数を使って読み込みます。ここではCalendarウィジェットのdijit._Calendarクラスを読み込んでいます。
- Calendarウィジェットを表示したい部分のHTMLマークアップでdojoType属性を指定し、Dojoウィジェットのクラス名を宣言します。ここではdojoType=”dijit._Calendar”としています。
- さらにそのDojoウィジェットに初期値として与えられる属性などがある場合には、同じ要素の中で属性を指定します。ここでは、dayWidth=”narrow”(カレンダーのヘッダー部分の曜日を短く表記)を例として指定しています。
- (オプション) 必要に応じて、作成したウィジェットを利用するためのロジックを実装します。ここでは、Calendarウィジェットで日付が選択されたときに呼び出されるonValueSelected関数に対してdojo.connectを行い、選択された日付をフォーマットして入力フィールドにセットするようにしています。
ここからはXPagesでDojoウィジェットを利用する方法を、サンプルを交えながら紹介していきます。本稿で紹介するのは、以下の2つのサンプルです。
- サンプル1 (基本編): Calendarウィジェットを使用して、図4の例と同様のページをXPageで作成する
- サンプル2 (応用編): Treeウィジェットを使用して、Dominoアプリケーション内に保存された社員の所属部門情報をツリー形式で表示し、さらにドラッグ&ドロップで所属部門を変更できるようにする
サンプルの完成版を含んだアプリケーションであるDojoWidgetSample.nsfは、本稿末尾のリンクからダウンロード可能ですのであわせてご覧ください。なお、このサンプルはNotes/Dominoのバージョン8.5.1をベースに作成しており、以下で紹介する手順もバージョン8.5.1での手順となります。
まず基本編として、図4で紹介したCalendarウィジェットの例と同様のページを、XPagesを使って実装します。ここではリスト2のサンプルコードで紹介したa~fのステップに沿って手順を紹介します。完成版はサンプルアプリケーションのCalendar.xspになります。
djConfig=”parseOnLoad:true”属性の追加、およびtundraテーマの読み込み
はじめに、リスト2のサンプルコードのポイントaとbの部分を実装します。本稿の最初で紹介したように、dojo.jsはXPageで作成したページにデフォルトで読み込まれていますが、djConfig=”parseOnLoad:true”属性はデフォルトでは付いていません。これを追加するには、XPageのデザイン画面上でキャンバス部分に相当する「XPage」コントロールを選択した状態でプロパティビューを開き、「すべてのプロパティ」タブの中の「基本」>「dojoParseOnLoad」プロパティをtrueにセットします(図5)。また、同じ「すべてのプロパティ」タブの中で、「基本」>「dojoTheme」プロパティをtrueにセットすると、tundraテーマがページに読み込まれるようになります(図5)。
図5. dojoParseOnLoadとdojoThemeプロパティをtrueに
dojo.require(“dijit._Calendar”) コードの追加
次に、リスト2のサンプルコードのポイントcのdojo.require(“dijit._Calendar”)部分を実装します。この部分はクライアントサイドのJavaScriptなので、スクリプトライブラリのクライアントサイドJavaScriptの中などでdojo.require(“dijit._Calendar”)というコードをそのまま書いても動作しますが、コードを書かずにプロパティで設定する方法があります。先ほどと同じく「XPage」コントロールのプロパティビューの「すべてのプロパティ」タブの中で、「基本」>「resources」プロパティで、「+」ボタンをクリックして「xp:dojoModule」を追加し、追加されたdojoModuleの「基本」>「name」プロパティにロードしたいDojoウィジェットのクラス名である「dijit._Calendar」を設定します(図6)。これにより、このXPageを表示した際のHTMLの中に、dojo.require(“dijit._Calendar”)というJavaScript文が埋め込まれるようになります。
図6. resourcesプロパティにdojoModuleを追加
HTMLマークアップのdojoType属性およびDojoウィジェット属性の追加
次に、リスト2のサンプルコードのポイントdとeのHTMLマークアップ部分を実装します。Calendarウィジェットの表示部分には、図7に示すように「パネル」コントロールを配置します。「パネル」コントロールは、表示されるHTMLの中では<div>要素になります。この「パネル」コントロールを選択してプロパティビューの「すべてのプロパティ」タブを開くと、「dojo」>「dojoType」というプロパティがあります。ここに、dojoType属性で指定していた「dijit._Calendar」というCalendarウィジェットのクラス名を指定します(図7)。また、同じ「すべてのプロパティ」タブの中の、「dojo」>「dojoAttributes」プロパティでDojoウィジェットの属性を設定することができます。ここではdayWidth=”narrow”という属性を追加するために、「dojoAttributes」プロパティで「+」ボタンをクリックして「dojoAttribute」を1つ追加し、「name」に「dayWidth」を、「value」に「narrow」を設定します(図7)。
図7. dojoTypeとdojoAttributeプロパティの設定(バージョン8.5.1のみ)
ここでは「パネル」コントロールを使用しましたが、dojoTypeおよびdojoAttributesプロパティを設定できるコントロールは他にも「ボタン」コントロール(<button>要素)、「スパンコンテンツ」コントロール(<span>要素)、「ブロックレベルコンテンツ」コントロール(<div>要素、「パネル」よりもシンプルで設定項目が少ない)などがあります。「スパンコンテンツ」コントロールと「ブロックレベルコンテンツ」コントロールは、デフォルトでは「コントロール」ビューに表示されていませんが、「その他…」を配置したときに表示される「コントロールの作成」ダイアログの中から選択することができます(図8)。
図8. 「スパンコンテンツ」コントロールと「ブロックレベルコンテンツ」コントロール
なお、このdojoTypeおよびdojoAttributeプロパティは、Notes/Dominoバージョン8.5.1のXPagesで新しく追加されたプロパティです。そのため、バージョン8.5では利用することができません。バージョン8.5では代わりに、<div dojoType=”dijit._Calendar dayWidth=”narrow”/>というタグをそのままHTMLとしてXPageに埋め込みます。埋め込む方法は、XPageを「ソース」で編集して埋め込む(図9)か、あるいは計算結果フィールドを利用して埋め込む(図10)かのどちらかになります。
図9. XPageを「ソース」で編集してHTMLを直接埋め込み(バージョン8.5)
図10. 計算結果フィールドのカスタム値としてHTMLを埋め込み(バージョン8.5)
dojo.connectを使ったJavaScriptロジックの追加
最後に、リスト2のサンプルコードのポイントfのdojo.connectによるJavaScriptロジック部分を実装します。XPageに<script>要素によるJavaScriptロジックを埋め込むには、「出力スクリプト」コントロールを使用します。「出力スクリプト」コントロールもデフォルトでは「コントロール」ビューに表示されていませんが、「その他…」を選択したときに表示される「コントロールの作成」ダイアログの中から選択することができます(図11)
図11. 「出力スクリプト」コントロールの配置
配置した「出力スクリプト」コントロールを選択した状態でプロパティビューを開き、「すべてのプロパティ」タブの中の「データ」>「value」プロパティの「値」フィールドからスクリプトエディタを起動し、リスト3に示したJavaScriptを入力します(図12)。このJavaScriptはリスト2のfのものとほぼ同じですが、以下の2点を変更しています。
- dojo.addOnLoad関数の代わりに、XSP.addOnLoad関数を利用しています。dojo.addOnLoad関数はdojoがロードされてから呼び出されることが保証されていますが、XSP.addOnLoad関数は、dojoだけでなくXPage関連のライブラリもロードが完了してから実行されることが保証されます。
- dijit.byId関数およびdocument.getElementById関数の引数で指定しているIDを、#{id:xxxx}という形式に変更しています。XPagesでは、各コントロールに対してDomino Designer上で設定した名前を元に、実際にHTMLとして表示される際のDOM IDが自動生成されます。この自動生成されたDOM IDを取得するために#{id:xxx}という記述を使用します。例えば、「calendar」という名前の「パネル」コントロールについて、表示時のDOM IDを取得するには「#{id:calendar}」と記述します。詳しくは、Domino Designerヘルプの「Lotus Domino Designer XPage および Eclipse ユーザーガイド」>「XPages のスクリプト記述」>「クライアントサイドのスクリプト」を参照してください。
図12. 「出力スクリプト」コントロールのvalueプロパティにJavaScriptロジックをセット
リスト3. 出力スクリプトで設定したdojo.connect部分のJavaScriptロジック例
XSP.addOnLoad(function(){
dojo.connect(dijit.byId("#{id:calendar}"), "onValueSelected", function(date) {
var formattedDate = dojo.date.locale.format(date, {formatLength: "medium",selector: "date"});
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
document.getElementById("#{id:selectedDate}").value = formattedDate;
});
});
|
以上でCalendarウィジェットのサンプルは完成です。Webブラウザを利用して完成したXPageにアクセスし、動作を確認してください。
次に応用編として、TreeウィジェットをXPagesで利用する方法を紹介します。ここで紹介するサンプルは、図13のように、Treeウィジェットを使用してDominoアプリケーション内に保存された社員の所属部門情報をツリー形式で表示し、さらにドラッグ&ドロップで所属部門を変更する機能を実装しています。
図13. Treeウィジェットを利用したサンプル
Treeウィジェットをはじめとしたデータを可視化するDojoウィジェットでは、データの取得や更新をAJAXで行うことが多く、そのためのRESTサービスなどをサーバー側に用意するのが一般的です。そこで本サンプルでも、ツリー形式の社員所属部門情報の取得サービス、およびドラッグ&ドロップ時の所属部門更新サービスを作成し、TreeウィジェットからこれらのサービスにAJAXでアクセスして利用するようにします。
サンプル2-1. Treeウィジェットで表示するデータをJSONで返すサービスをXPageで作成する
はじめに、ツリー形式の社員所属部門情報を、Treeウィジェットで表示できるようなJSON形式のデータとして返すサービスを作成します。基本的にXPageはWebブラウザからアクセスされ、その上でページを表示するためのHTMLデータを返します。しかし実装を工夫することにより、HTMLデータを返さずにJSONやXMLを返すようにすることも可能です。この方法を利用して、XPageでJSONデータを返すサービスを作成してみます。完成版はサンプルアプリケーションのListEmployees.xspになります。
まず、「XPage」コントロールのプロパティビューの「すべてのプロパティ」タブの中で、「基本」>「rendered」プロパティをfalseにします(図14)。この設定により、表示のためのHTMLデータが何も出力されなくなります。この状態でブラウザによるプレビューを行うと真っ白な画面が表示され、HTMLのソースを見ると何のデータも返されていないことが分かります。
図14. XPageのrenderedプロパティをfalseにしてHTMLデータを返さないように設定
次にJSONデータを返す部分の実装を行います。「XPage」コントロールのイベントビューを開き、イベントリストの中の「ページ」>「afterRenderResponse」イベントの中で、リスト4のようにサーバーサイドJavaScriptを記述します(図15)。XPagesがJSF(Java Server Faces)の技術をベースにしていることを利用して、JSFが持っているレスポンスのデータを書き込むためのResponseWriterオブジェクトを取得して、JSONデータを文字列として直接書き出しています。
図15. XPageのafterRenderResponseイベント
リスト4. XPageのafterRenderResponse イベントでJSONデータを返すためのサーバーサイドJavaScript例
var extContext = facesContext.getExternalContext();
// ResponseのContentTypeおよびHeaderの指定
var response = extContext.getResponse();
response.setContentType("application/json");
response.setHeader("Cache-Control", "no-cache");
// ResponseのWriterにデータを書き込み
var writer = facesContext.getResponseWriter();
writeEmployeeTree(writer); // JSONデータの書き込み
writer.flush();
writer.endDocument();
|
リスト4のデータの書き込み部分で使用している「writeEmployeeTree(writer)」という関数はリスト5に示したもので、サンプルアプリケーションの中ではスクリプトライブラリ「tree.jss」に定義してあります。この関数は、図16に示した部門一覧ビューと社員一覧ビューのデータ(これらはあらかじめサンプルのNotesアプリケーション内に用意されています。)を元に、ツリー形式の社員所属部門情報をResponseWriterオブジェクトにJSON形式のデータとして出力します。
図16. 社員所属部門情報を生成するのに利用した部門一覧ビューと社員一覧ビュー
リスト5. JSONデータをwriterに書き込むサーバーサイドJavaScript例
// すべての社員のツリーデータを書き出す関数
function writeEmployeeTree(writer) {
try {
writer.append('{identifier:"id", label:"name", items:[');
writeEmployeeTreeInDept(writer, "000"); // 最上位の部門はここでは'000'
writer.append("]}");
} catch (e) {
print(e);
}
}
// 指定された部門下の社員のツリーデータを書き出す関数
function writeEmployeeTreeInDept(writer, deptId) {
// ビューから指定された部門の子部門および所属社員のCollectionを取得
var deptCol = database.getView("DeptsByParentDept").getAllEntriesByKey(deptId);
var empCol = database.getView("EmpsByDept").getAllEntriesByKey(deptId);
// 子部門データの書き出し
var deptEntry = deptCol.getFirstEntry();
while (deptEntry != null) {
var deptDoc = deptEntry.getDocument();
var childDeptId = deptDoc.getItemValueString("deptID");
var childDeptName = deptDoc.getItemValueString("deptName");
writer.append('{id:"' + childDeptId + '", name:"' + childDeptName + '", type:"dept", ');
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
// 子部門のさらに子供の要素を再帰的に書き出し
writer.append("children:[");
writeEmployeeTreeInDept(writer, childDeptId); // 再帰呼び出し
writer.append("]}");
deptEntry = deptCol.getNextEntry(deptEntry);
if (deptEntry != null || empCol.getCount() > 0) writer.append(", ");
}
// 所属社員データの書き出し
if (empCol.getCount() > 0) {
var empEntry = empCol.getFirstEntry();
while (empEntry != null) {
var empDoc = empEntry.getDocument();
var empID = empDoc.getItemValueString("employeeID");
var empName = empDoc.getItemValueString("employeeName");
writer.append('{id:"' + empID + '", name:"' + empName + '", type:"employee"}');
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
empEntry = empCol.getNextEntry(empEntry);
if (empEntry != null) writer.append(", ");
}
}
}
|
以上でサービスの実装は完成です。ListEmployees.xspにアクセスすると、リスト6に示すようなJSONデータが返ってきます。(リスト6の改行およびインデントはデータを見やすくするために後から手動で追加したもので、実際のサンプルでは改行やインデントがないデータが返されます。)
リスト6. ListEmployees.xspが実際に返すJSONデータ
{
identifier:"id", label:"name", items:[
{id:"100", name:"営業部", type:"dept", children:[
{id:"110", name:"第1営業部", type:"dept", children:[
{id:"111", name:"ソフトウェア営業部", type:"dept", children:[
{id:"0003", name:"営業三郎", type:"employee"},
{id:"0004", name:"営業四郎", type:"employee"}
]},
{id:"112", name:"ハードウェア営業部", type:"dept", children:[
{id:"0005", name:"営業五郎", type:"employee"},
{id:"0006", name:"営業六郎", type:"employee"}
]},
{id:"0002", name:"営業二郎", type:"employee"}
]},
{id:"120", name:"第2営業部", type:"dept", children:[
{id:"0007", name:"営業七郎", type:"employee"},
{id:"0008", name:"営業八郎", type:"employee"}
]},
{id:"0001", name:"営業一郎", type:"employee"}
]},
{id:"200", name:"研究開発部", type:"dept", children:[
{id:"210", name:"ソフトウェア開発部", type:"dept", children:[
{id:"0010", name:"開発二郎", type:"employee"},
{id:"0011", name:"開発三郎", type:"employee"}
]},
{id:"220", name:"ハードウェア開発部", type:"dept", children:[
{id:"0012", name:"開発四郎", type:"employee"},
{id:"0013", name:"開発五郎", type:"employee"}
]},
{id:"0009", name:"開発一郎", type:"employee"}
]}
]
}
|
サンプル2-2. Data APIと組み合わせてTreeウィジェットを利用する
次に、サンプル2-1で作成した表示用データを取得するためのサービスを利用して、Treeウィジェットによってツリー形式にデータを表示させるXPageを作成します。完成版はサンプルアプリケーションのTree1.xspになります。
作成したJSONデータ取得サービスへのアクセスにはDojo Toolkitが提供するData APIを使用します。ここで使用するのはdojo.data.ItemFileWriteStoreというData APIクラスで、url属性にサービスのURLを指定しておくことでAJAXによってデータを取得する機能を持っています。このData APIクラスを使ってサンプル2-1で作成したサービスにアクセスするTreeウィジェットを実装します。
通常のHTMLで実装する場合にはリスト7のようになります。Treeウィジェットの部分は「dijit.Tree」というクラスを使用しています。またData APIの部分も、HTMLマークアップによって指定することが可能です。Treeウィジェットの一般的な使用法について詳しく知りたい方は、こちらを参照してください。
リスト7. サンプル2-1で作成したサービスにData APIを通じてアクセスするTreeウィジェットのHTMLソース例(一部省略)
<script type="text/javascript">
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require("dijit.tree.ForestStoreModel");
dojo.require("dijit.Tree");
function getIcon(item, opened) {
try {
return (!item) ? "deptIcon" : (treeStore.hasAttribute(item, "type")
&& "employee" == treeStore.getValue(item, "type")) ? "empIcon" : "deptIcon";
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
} catch (e) {
return "deptIcon";
}
};
</script>
<body class=”tundra”>
<div dojoType="dojo.data.ItemFileWriteStore" jsId="treeStore" url="ListEmployees.xsp"/>
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
<div dojoType="dijit.tree.ForestStoreModel" jsId="treeModel" store="treeStore"
rootId="root" childrenAttrs="children"/>
<div class=”treeOuter”>
<div dojoType="dijit.Tree" jsId="tree" model="treeModel"
getIconClass="getIcon" showRoot="false"/>
</div>
</body>
|
このリスト7の内容をXPageで実装する方法は、サンプル1のCalendarウィジェットの例の場合と同様です。dojo.require部分は「基本」>「resources」>「dojoModule」に、それ以外のJavaScriptは「出力スクリプト」コントロールに、dojoTypeとDojoウィジェット属性部分は「dojo」>「dojoType」および「dojoAttributes」に、それぞれ定義します。例えば、リスト7でのTreeウィジェットの本体であるdijit.Treeを指定した<div>要素の部分は、XPage上では「ブロックレベルコンテンツ」コントロールを使用して図17のように実装できます。
図17. Treeウィジェット表示部分の「ブロックレベルコンテンツ」コントロールのXPage上での設定
Treeウィジェット表示部分の実装は以上です。Tree1.xspをプレビューすると、図13に示したように社員所属部門情報がツリー形式で表示されるはずです。ここではまだドラッグ&ドロップはできません。
サンプル2-3. データ更新用のサービスをXPageで作成する
次に、Treeウィジェット上でのドラッグ&ドロップ操作時に利用する、社員所属部門の更新サービスをXPageで作成します。完成版はサンプルアプリケーションのUpdateEmployee.xspになります。
更新サービスの実装は、サンプル2-1で紹介したJSONデータ取得サービスの実装方法と似ています。異なるのは、afterRenderResponseイベントの中のサーバーサイドJavaScriptの実装のみです。ここではリスト8のように、社員IDと新しい所属部門ID がempId=0001&deptId=100というパラメータでPOSTされてきた際に、社員所属部門を更新する機能を実装します。サンプル2-1のJSONデータ取得サービスはHTTPアクセスのResponseを生成してデータを返すサービスでしたが、今回の更新サービスは、HTTPアクセスのRequestを受け取って処理を行うサービスとなっています。
リスト8. XPageのafterRenderResponse イベントでデータ更新サービスを実装したサーバーサイドJavaScript例
var extContext = facesContext.getExternalContext();
// Requestの取得
var request = extContext.getRequest();
if ("POST" == request.getMethod()) { // POST のみ許可
// Postされたパラメータの取得
var empId = param.get("empId");
var deptId = param.get("deptId");
if (empId && deptId) { // パラメータが指定されていれば
var empDoc = database.getView("Emps").getDocumentByKey(empId);
var deptDoc = database.getView("Depts").getDocumentByKey(deptId);
if (empDoc && deptDoc) { // 実際に存在するか確認
// 所属部門の更新
empDoc.replaceItemValue("deptID", deptId);
empDoc.save();
}
}
}
|
サンプル2-4. Treeウィジェット上でドラッグ&ドロップによりデータ更新できるようにする
最後に、Treeウィジェット上で社員ノードをドラッグ&ドロップ操作で移動可能にし、ドロップされた際にサンプル2-3で作成した社員所属部門の更新サービスをAJAXで呼び出し、データの更新を行うようにします。完成版はサンプルアプリケーションのTree2.xspになります。
ここでもまず通常のHTMLでの実装をベースにします。Treeウィジェット上でドラッグ&ドロップ操作を可能にするためには、通常のHTMLではリスト9の内容を追加する必要があります。Treeウィジェットでのドラッグ&ドロップ用にdijit._tree.dndSourceというクラスが用意されており、それを利用しています。Treeウィジェットでのドラッグ&ドロップの実装方法の詳細については、こちらを参照してください。
リスト9. Treeウィジェットで社員ノードのドラッグ&ドロップ操作を可能にするためのHTMLソース例(リスト7からの追加・変更部分のみ)
<script type="text/javascript">
dojo.require("dijit._tree.dndSource");
function dndAccept(source, nodes) {
var type = "";
var widget = dijit.getEnclosingWidget(nodes[0]);
if (widget && widget.item) {
type = treeStore.getValue(widget.item, "type");
}
return (type == "employee") ? true : false;
};
function itemTreeCheckItemAcceptance(node, source) {
var type = "";
var widget = dijit.getEnclosingWidget(node);
if (widget && widget.item) {
type = treeStore.getValue(widget.item, "type");
}
return (type == "dept") ? true : false;
};
</script>
<body class=”tundra”>
<div dojoType="dojo.data.ItemFileWriteStore" jsId="treeStore" url="ListEmployees.xsp"/>
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
<div dojoType="dijit.tree.ForestStoreModel" jsId="treeModel" store="treeStore"
rootId="root" childrenAttrs="children"/>
<div class=”treeOuter”>
<div dojoType="dijit.Tree" jsId="tree" model="treeModel"
getIconClass="getIcon" showRoot="false"
dndController="dijit._tree.dndSource" checkAcceptance="dndAccept"
checkItemAcceptance="itemTreeCheckItemAcceptance"/>
</div>
</body>
|
このリスト9の内容もサンプル1やサンプル2-2のときと同様、XPageでの実装に変換可能です。例えば、dijit.Treeを指定した<div>要素の更新部分は、XPage上の「ブロックレベルコンテンツ」コントロールで図18のように更新されます。
図18. Treeウィジェット表示部分の「ブロックレベルコンテンツ」コントロールのXPage上での設定(更新版)
これで、Treeウィジェット上での社員ノードのドラッグ&ドロップによる移動が可能になりました。最後に、ドロップされた際に、サンプル2-3で実装したデータ更新サービスをAJAXで呼び出すように変更します。ドロップの際に処理を実行するために、リスト10のようにTreeウィジェットが持つdndControllerというオブジェクトのonDndDrop関数にdojo.connectし、この中でdojo.xhrPost関数を利用してデータ更新サービスを呼び出すようにします。
リスト10. dndControllerのonDndDrop関数にdojo.connectしてドロップ時にデータ更新サービスを呼び出すJavaScript例
XSP.addOnLoad(function() {
dojo.connect(tree.dndController, "onDndDrop", function (source, nodes, copy) {
var empId = null, deptId = null;
// DropしたSourceのEmployeeノードから社員IDを取得
var sourceWidget = dijit.getEnclosingWidget(nodes[0]);
if (sourceWidget && sourceWidget.item) {
empId = treeStore.getValue(sourceWidget.item, "id");
}
// DropされたTargetのDeptノードから部門IDを取得
var targetWidget = dijit.getEnclosingWidget(this.current);
if (targetWidget && targetWidget.item) {
deptId = treeStore.getValue(targetWidget.item, "id");
}
// 変更要求をPOST
if (empId && deptId) {
dojo.xhrPost({
url: "UpdateEmployee.xsp",
postData: "empId=" + empId + "&deptId=" + deptId,
load: function() {},
error: function() {}
});
}
});
});
|
以上でドラッグ&ドロップによるデータ更新の実装は完了です。図13に示したように、社員を別の部門にドラッグ&ドロップで移動すると、実装した機能によりDominoアプリケーション内の情報が更新されるため、ブラウザをリフレッシュしても更新されたデータが正しく表示されます。
本稿では、DojoウィジェットをXPagesで利用する方法を、CalendarウィジェットとTreeウィジェットのサンプルを交えながら紹介しました。今回紹介したTreeウィジェットを含め、データを直感的でわかりやすい形で可視化することができるDojoウィジェットを利用すると、今までのDomino上で動作するWebアプリケーションでは実現が難しかった、Web2.0スタイルの見栄えと機能を備えたアプリケーションを開発することが可能になります。また、今回紹介したようなDojoウィジェット以外にも、境界線をドラッグ&ドロップで移動することができるSplitContainerや、アコーディオン形式で内容を表示するAccordionContainerなど、ページのレイアウトを調整するためのコンテナー機能を持ったDojoウィジェットなども数多くあります。これを機に、XPagesの中で最大限にDojoを活用した、よりリッチなXPagesアプリケーションの開発に取り組んでいただければ幸いです。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| サンプルコード | dojo_widget_sample_nsf.zip | 47KB | HTTP |
XPages
- IBM Lotus Notes/Domino 8.5 におけるアプリケーション開発 (developerWorks記事)
- XPages による Web アプリケーション開発: 前編、後編 (developerWorks記事)
- Lotus Domino Designer での XPages 機能の活用 (developerWorks記事)
- XPagesでのアプリケーション開発の実際 (developerWorks記事)
- XPages Straight Up (英語) (developerWorks記事)
- IBM Lotus Notes/Domino 8.5.1における XPages 新機能 (developerWorks記事)
- Lotus Notes and Domino Application Development Wiki (英語)
- The Dojo Toolkit: Dojo Toolkit のサイト (英語)
- DojoCampus: Official Dojo Documentation (英語)
- IBM developerWorks: Wikis - Software Technology Japan - Dojoツールキット
- Dojoツールキットで始めるオブジェクト指向
- Dojo ToolkitのDataGridを使いこなす