カスタムセルの利用
GWT 2.1 で導入されたセル (Cell) 系ウィジェットでは、セルの種類 で挙げたセルの他にも、 自分で定義したセルも利用することができます。
例えば、Employee というクラスを表示するための EmployeeCell というセル・カスタムクラスを定義して、 そのセルリスト (CellList)を作成することができます。
上のスクリーンショットでは、(少々見栄えは悪いですが・・・(苦笑))テーブルが縦に並んでおり、その中にデータが表示されていることがわかります。 これはテーブル一つ一つがカスタムのセル (EmployeeCell) で定義されています。
このようなカスタムセルの作り方を説明します。
カスタムセルをセルリストで使う手順
カスタムセルをセルリストで使うための手順は、次の通りです。
- セルクラスの定義 (今回の例では EmployeeCell クラスの定義)
- セルリストのコンストラクタにカスタム・セルクラス・オブジェクトを渡しセルリストを作成
- セルリストの setRowData メソッドでデータをセットする
ご覧の通り、TextCell などの GWT ビルトインのセルクラスを利用する場合と全く同じ手順でカスタムセルが扱えます。
カスタムセルクラスの定義
まず、前提としてここで扱う Employee クラスを定義しておきます。もちろんこれは Employee という名前のクラスである必要は全くありません。 あなたの環境、要件にあわせて書き換えてください。
public class Employee { private String employeeID; private String firstName; private String lastName; public Employee(String employeeID, String firstName, String lastName){ this.employeeID = employeeID; this.firstName = firstName; this.lastName = lastName; } public String getEmployeeID(){ return employeeID; } public String getFirstName(){ return firstName; } public String getLastName(){ return lastName; } }
ここでは Employee (従業員) クラスは、社員番号 (EmployeeID) と名前 (First Name, Last Name) を受取り、 アクセサを通して取得できるだけのクラスとしています。
ここで作る EmployeeCell というカスタムセルクラスでは、Employee の情報を表示するものとします。 今回は HTML の table タグを使って、Employee の情報を表示します。
実装は次のようになります。
class EmployeeCell extends AbstractCell<Employee> { @Override public void render(Employee value, Object key, SafeHtmlBuilder sb) { if(value == null){ return; } sb.appendHtmlConstant("<table border=\"1\"><tr><td>"); sb.appendHtmlConstant(value.employeeID); sb.appendHtmlConstant("</td><td>"); sb.appendHtmlConstant(value.lastName.toUpperCase() + ", " + value.firstName); sb.appendHtmlConstant("</td></tr></table>"); } }
先に言っておきますが、これは一応動きますがあまり良い実装ではないので、後で直します。
さて、まずカスタムセルクラスは AbstractCell (com.google.gwt.cell.client.AbstractCell) を派生し、型を指定します。 ここでは <Employee> として Employee クラスに対するカスタムセルクラスであることを指定します。 次に render メソッドをオーバーライドします。第一引数に Employee クラスのオブジェクトが、第三引数に HTML 構築用の SafeHtmlBuilder が渡されます。
このセルで表示されるオブジェクトは第一引数に渡されます。第三引数の SafeHtmlBuilder に、 このセルの HTML 表現を append すれば OK です。 ここでは、上のコードを見てわかる通り、table タグを使って Employee 情報を表示しています。
カスタムセルリストの利用コード
上で作成したカスタムセルをセルリストで使う例をみてください。
@Override public void onModuleLoad() { EmployeeCell empCell = new EmployeeCell(); CellList<Employee> cellList = new CellList<Employee>(empCell); final SingleSelectionModel<Employee> selectionModel = new SingleSelectionModel<Employee>(); cellList.setSelectionModel(selectionModel); selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { @Override public void onSelectionChange(SelectionChangeEvent event) { Window.alert("Clicked! " + selectionModel.getSelectedObject()); } }); List<Employee> list = new ArrayList<Employee>(); list.add(new Employee("000001", "Keisuke", "Oyama")); list.add(new Employee("000002", "Ichiro", "Suzuki")); list.add(new Employee("000003", "Grace", "Oyama")); cellList.setRowData(0, list); RootPanel.get().add(cellList); }
標準的な TextCell を使うときと同様です。簡単ですね。
さて、ひとつ重大な問題を残していますので、ここでもう一度先のコードに戻ってその欠点をつぶしましょう。
SafeHtml によるサニタイズ
もし、データに HTML のタグが埋め込まれた場合にどうなるかみてみましょう。 先ほどのコード内のデータを渡す箇所で、次のようにタグを入れてみましょう。
List<Employee> list = new ArrayList<Employee>(); list.add(new Employee("000002", "<b>Ichiro</b>", "Suzuki")); ...
この結果、次のようにタグが生きて、文字が太文字で表示されてしまいました。
このようにデータ内に埋め込まれた HTML は、クロスサイトスクリプティングなどのセキュリティの問題を始め、 意図せぬ結果を招きます。このためデータ部は正しくタグを取り除くなどの処理が必要です。 こうした処理をサニタイズと呼びます。
GWT ではサニタイズされた文字列を取得するための、SafeHtmlUtils というヘルパークラスが用意されています。 SafeHtmlUtils の fromString メソッドを用いて、SafeHtml を取得し SafeHtml の asString() メソッドで文字列を取得します。
SafeHtmlUtils を用いて上記コードを書き直すと、次のようになります。
@Override public void render(Employee value, Object key, SafeHtmlBuilder sb) { if(value == null){ return; } sb.appendHtmlConstant("<table border=\"1\"><tr><td>"); sb.appendHtmlConstant( SafeHtmlUtils.fromString(value.employeeID).asString()); sb.appendHtmlConstant("</td><td>"); sb.appendHtmlConstant( SafeHtmlUtils.fromString(value.lastName.toUpperCase() + ", " + value.firstName).asString()); sb.appendHtmlConstant("</td></tr></table>"); }
この結果、次のように正しく < などの文字をエンコードできました。