JSP タグ ライブラリのさまざまな局面を、単純かつ強力なメタデータ ファイルを使用して、カスタマイズできるようになりました。最も注目に値するのは、Velocity HTML 表示テンプレートを記述して、JSP デザイン エディタにおける JSP タグや JSF コンポーネントの表示をカスタマイズできるようになった点です。
このトピックの内容は以下のとおりです。
Workshop 製品には、標準的なタグ ライブラリ (HTML、JSP、JSTL、Struts、JSF など) の多くが統合されています。この統合により、IDE は以下のようなものを制御できます。
このトピックでは、他の JSP タグ ライブラリや JSP コンポーネント向けに IDE をカスタマイズする方法を示します。タグ ライブラリのカスタマイズは、以下の要件を満たす、xml 形式の Tag Library Extra Information (tlei) ファイルで指定されます。
たとえば、タグ ライブラリ「/WEB-INF/app.tld」は、ファイル「/WEB-INF/app.tlei」または「/WEB-INF/nitrox/app.tlei」でカスタマイズできます。
以下は、tlei ファイルの例です。
<tlei> <css-uri>app.css</css-uri> <tag name="myTag"> <display-name>My Tag</display-name> <small-icon>images/myTag.gif</small-icon> <!-- render the tag as 3 text fields separated by / --> <rendering-template><![CDATA[ <input type="text" name="month" size="2"/> / <input type="text" name="day" size="2"/> / <input type="text" name="year" size="4"/> ]]></rendering-template> <attribute name="myAttr"> <sub-type>uri</sub-type> </attribute> </tag> </tlei>
以下の節では、さまざまな tlei タグについて説明します。
タグ表示では、タグが JSP エディタのデザイン ビューでどのように表示されるかを制御します。デフォルトでは、エディタはカスタム タグを、タグ アイコンおよびタグ名が入った枠付きのボックスとして表示します。タグ表示は、tlei ファイルでは以下のようにカスタマイズできます。
デフォルトでは、デザイン エディタはカスタム タグを、タグ アイコンとタグのプレフィックス:名前をラベルとして含む、枠付きのボックスとして表示します。このラベルは、rendering-label タグを使用してカスタマイズできます。
rendering-label タグには、任意のテキストを、動的に値を求められる以下の特殊な表現のいずれかと併用して、含めることができます。
${tag.name}: タグ名と置換される。
${tag.fullName}: タグ プレフィックスおよびタグ名と置換される (たとえば、h:commandView )。
${tag.displayName}: display-name タグを使用して指定されるタグ表示名と置換される。
表示名が指定されていない場合は、タグ名が使用されます。
${tag.attr.attrName}: attrName という名前の属性の属性値と置換される。 たとえば、${tag.attr.myAttr} となります。 「|」文字で区切った属性名のリストを指定することもできます。最初の非 null 属性値が、このパターンと置換されます。例を示します。
name
例を示します。
<tlei> <tag name="myTag"> <rendering-label>${tag.fullName} (${tag.attr.page})</rendering-label> </tag> </tlei>
Velocity テンプレートを、表示 JSP ソース コードとして使用するよう、指定できます。一般に、このテンプレートには任意の HTML/JSP が、条件/反復コンテンツのための Velocity 表現と共に含まれます。表示テンプレートを記述するのに、Velocity に関する広範な経験は必要ありません。この節に記載の例では、多くの一般的なケースを示します。Velocity のさらに高度な使い方については、「Velocity User Guide」を参照してください。このテンプレートには、必ずしも Velocity 表現が含まれていなければならないわけではありません。たとえば、日付を表すタグを、とにかく 3 つの編集フィールドとして表示したい場合は、次のように指定できます。
<tlei> <tag name="myTag"> <rendering-template><![CDATA[ <input type="text" name="month" size="2"/> / <input type="text" name="day" size="2"/> / <input type="text" name="year" size="4"/> ]]></rendering-template> </tag> </tlei>テンプレートのコンテンツは
${tag.name}: タグ名として評価される。例を示します。 <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
<span style="color: red">${tag.name}</span>
]]></rendering-template>
</tag>
</tlei>
ここでは、タグ名が赤色で表示されます。
${tag.fullName}: タグ プレフィックスおよびタグ名 (たとえば、h:commandView) として評価される )。
${tag.displayName} : display-name タグを使用して tlei ファイル内で指定されるタグ表示名として評価される。
表示名が指定されていない場合は、タグ名が使用されます。
${tag.missingAttr("attrName")}: タグに所定の属性がない場合、ブール式の結果は true になる。
${tag.attr("attrName")}: attrName という名前の属性の属性値として評価される 。
タグに所定の属性がなければ、空の文字列として評価されます。例を示します。 <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
#if (!$tag.missingAttr("attr1"))
${tag.attr("attr1")}
#else
${tag.attr("attr2")}
#end
]]></rendering-template>
</tag>
</tlei>
ここでは、タグ内で指定されていない場合以外は、属性 attr1 の値を表示します。
指定されていない場合は、属性 attr2 の値が表示されます 。
${tag.attrInt("attrName")}:
${tag.attr("attrName")} と同じだが、値を整数に変換する。タグに所定の属性がないか、値が整数に変換できない場合は、0 になります。場合によっては、タグ属性値に基づく反復コンテンツの生成に使用できます。
${tag.empty}: タグに子 (本体コンテンツ) がなければ true になるブール式。
${tag.childrenTags}: 子タグのリストとして評価される。子タグがなければ、空のリストになります。通常は、返されたリストを反復させて、反復変数をタグ変数として使用します。例を示します。 <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
#set ($count = 0)
#foreach ($childTag in $tag.childrenTags)
#if (${childTag.name} == "myOtherTag")
#set ($count = $count + 1)
#end
#end
Found ${count} myOtherTag tags.
]]></rendering-template>
</tag>
</tlei>
ここでは、特定の名前を持つ子タグの数を表示します。
${tag.childrenSource}: 子タグの JSP ソース コード、またはそれがなければ (つまり、タグに子タグがなければ) 空の文字列として評価される。たとえば、ツリー ノード タグは、次のように表示されることがあります。 <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
${tag.attr("label")}
#if (!${tag.empty})
<div style="margin-left: 30">${tag.childrenSource}</div>
#end
]]></rendering-template>
</tag>
</tlei>
ここでは、ノード ラベルを表示し、次に子ノード (存在する場合) をインデントして表示します。この例では、ネストされた子ツリー ノード タグは、同じマークアップ テンプレートを使用して再帰的に表示されます。
${tag.childTag(name, prefix,
attrName, attrValue)}: 所定のタグ名、タグ プレフィックス、および属性の名前/値に一致する最初の子タグとして評価される。例を示します。 <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
#set ($header = $tag.childTag("facet", "f", "name", "header"))
#if ($header) Found header facet: ${header.childrenSource}
#else Header facet not found!
#end
]]></rendering-template>
</tag>
</tlei>
ここでは、ヘッダに同等な名前を持つネストされた f:facet タグのコンテンツが表示されるか、それが見つからない場合はエラー メッセージが表示されます。 name
${tag.childTag(name,
prefix)}: (属性値が何であっても関係なく) 所定のタグ名およびタグ プレフィックスに一致する最初の子タグとして評価される。
${tag.url("uri")}: 所定の相対 URI に対応する絶対 URL として評価される。この URI は、テンプレートを含むファイルの場所を基準とした相対 URI (つまり、rendering-template タグを使用している場合は tlei ファイルを基準とした相対 URI、後述する rendering-template-uri タグを使用している場合はテンプレート ファイルを基準とした相対 URI) とする必要があります。
テンプレートに画像が含まれる場合は、画像ソースを計算するために url 関数を使用して、エディタから認識できるようにします。例を示します。 <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
<img src="${tag.url("images/myImage.gif")}"/>
<input type="text" name="" size="20"/> ]]></rendering-template>
</tag>
</tlei>
ここでは、画像とテキスト入力フィールドが表示されます。この例では、画像 myImage.gif が、images という名前のフォルダ内に置かれる必要があります。このフォルダは、tlei ファイルと同じディレクトリ (テンプレートが指定されている場所) に存在していなければなりません。
${tag.icon}: small-icon タグを使用する tlei ファイル内で指定されているタグ アイコンの絶対 URL として評価される。
rendering-template-uri タグを使用すると、独自のファイル内で表示テンプレートを指定できます。これは通常、表示テンプレートが複数のタグ間で共有されている場合や、表示テンプレートが大きい場合に、使用されます。テンプレート ファイルは、tlei ファイルの場所を基準として相対的に指定します。任意の名前と、任意のファイル拡張子を付けられます。例を示します。
<tlei> <tag name="myTag"> <rendering-template-uri>templates/myTag.vm</rendering-template-uri> </tag> </tlei>
この例では、ファイル myTag.vm は templates という名前のフォルダ内に配置される必要があります。このフォルダは、tlei ファイルと同じディレクトリに存在していなければなりません。もちろん、別個のテンプレート ファイルを使用する場合は、<rendering-template> および <![CDATA[ は不要です。
IDE が MyFaces JSF コンポーネントの一部に対して、どのように表示テンプレートを使用するかの例を、以下に示します。
x:commandNavigation
<a href="#">${tag.attr("value")}</a> #if (!$tag.empty) <div style="margin-left: 16">${tag.childrenSource}</div> #end
x:inputDate
#set ($type = ${tag.attr("type")}) #set ($styleClass = ${tag.attr("styleClass")}) #set ($style = ${tag.attr("style")}) #if (!($type == "time"))
<input type="text" name="day" size="8" class="$styleClass" style="$style"/> <select name="month" class="$styleClass" style="$style"/> <input type="text" name="year" size="10" class="$styleClass" style="$style"/> #if (${tag.attr("popupCalendar")} == "true") <input type="button" value="..."/> #end #end
#if ($type == "both" || $type == "time")
<input type="text" name="hour" size="10" class="$styleClass" style="$style"/> :<input type="text" name="minute" size="10" class="$styleClass" style="$style"/> :<input type="text" name="second" size="10" class="$styleClass" style="$style"/>
#end
x:dataScroller
#if (${tag.attr("renderAsPopup")} == "true")
<input type="text" name="${tag.attr("value")}" class="${tag.attr("styleClass")}" style="${tag.attr("style")}"/> <input type="button" value="..."/>
#else
<table class="${tag.attr("styleClass")}" style="${tag.attr("style")}>
<tr class="${tag.attr("monthYearRowClass")}">
<td><a href="#"><</a></td>
<td colspan="5">Month Year</td>
<td><a href="#">></a></td>
</tr> <tr class="${tag.attr("weekRowClass")}">
<td>Sun</td>
<td>Mon</td>
<td>Tue</td>
<td>Wed</td>
<td>Thu</td>
<td>Fri</td>
<td>Sat</td>
</tr> #foreach ($i in [0..4])
<tr>
#foreach ($j in [0..6])
#set ($day = $i * 7 + $j)
#if ($day <= 0)
<td class="${tag.attr("dayCellClass")}"></td>
#elseif ($day == 7)
<td class="${tag.attr("currentDayCellClass")}"><a href="#">$day</a></td>
#elseif ($day <= 31)
<td class="${tag.attr("dayCellClass")}"><a href="#">$day</a></td>
#end
#end
</tr>
#end
</table>
#end
x:dataScroller
#macro (facet $facetName)
#if ($tag.childTag("facet", "f", "name", $facetName))
<td>
#set ($facetTag = $tag.childTag("facet", "f", "name", $facetName))
<a href="#">$facetTag.childrenSource</a>
</td>
#end
#end <table><tr>
#facet("first")
#facet("fastrewind")
#facet("previous") #if ($tag.attr("paginator") == "true")
<td> <table cellpadding="1" cellspacing="1" class="${tag.attr("paginatorTableClass")}" style="${tag.attr("paginatorTableStyle")}"><tr>
#set ($max = $tag.attrInt("paginatorMaxPages"))
#if ($max < 2)
#set ($max = 2)
#end
<td class="${tag.attr("paginatorActiveColumnClass")}" style="${tag.attr("paginatorActiveColumnStyle")}">
<a href="#">1</a>
</td>
#foreach ($i in [2..$max])
<td class="${tag.attr("paginatorColumnClass")}" style="${tag.attr("paginatorColumnStyle")}">
<a href="#">$i</a>
</td>
#end
</tr></table> </td>
#end #facet("next")
#facet("fastforward")
#facet("last")
</tr></table> #foreach ($child in $tag.childrenTags)
#if (!($child.name == "facet"))
$child.source
#end
#end
タグ ライブラリの任意のタグに、標準的な CSS スタイルを関連付けることができます。CSS スタイルは、tlei タグ css-uri を使用して指定される css ファイル内で宣言されます
<tlei> <css-uri>app.css</css-uri> </tlei>次に、app.css ファイルに
タグ属性を tlei ファイル内でカスタマイズするには、サブ タイプと列挙を指定します。属性のカスタマイズ用には、2 つの tlei タグがあります。
<tlei> <tag name="myTag"> <attribute name="myAttr"> <enumeration>value1, value2</enumeration> </attribute> </tag> </tlei>この例では、列挙をタグ myTag の属性 myAttr に関連付けています。
<tlei> <global-attribute name="action"> <sub-type>jsf-action</sub-type> </global-attribute> </tlei>ここでは、タグ ライブラリにある任意のタグ内の action という名前の属性が、jsf-action サブ タイプを持つことが示されます。これは単に、すべての action 属性に対して attribute タグを使用することに代わるショートカットです。
IDE では、属性値の編集、属性値のナビゲーション、ページ検証と整合性チェック、および AppXRay 依存関係の分野において、属性値をより巧みに取り扱えるようになる、属性サブ タイプがあらかじめ定義されています。たとえば、属性に対し struts-action-mapping サブ タイプを指定すると、IDE は自動的に次のような処理を行います。
以下はあらかじめ定義されているサブ タイプと、それらに対応する属性値の説明です。
enumeration タグの使用により、属性値があらかじめ定義された一連の値に制限されることを指定できます。
<tlei> <tag name="myTag"> <attribute name="myAttr"> <enumeration>value1, value2</enumeration> </attribute> </tag> </tlei>
IDE は自動的に、以下の処理を行います。
デザイン エディタまたはソース エディタでカスタム タグを編集する場合、IDE はデフォルトではタグ属性値を修正できる標準的な [プロパティ シート] を表示します。多くの場合、特により豊富な JSF コンポーネントに関しては、属性の数が膨大なため、「頻繁に使用する」属性の編集には、より最適化の進んだ方法が必要となることがあります。カスタム タグ エディタを定義することで、まさにその目的が達せられます。メタデータを使用して、表示される属性と、それらの属性がどのようにグループ化されるかを指定します。メタデータは次に、[プロパティ シート] に加えて、ダイアログ方式の [スマート エディタ] の UI での表示に使用されます。一般に、タグ編集ダイアログは、メタデータ ファイルで指定する属性のためのエディタによって構成されます。各属性エディタは、編集コントロール (テキスト フィールド、コンボボックスなど) と、(タグ属性で説明したように) 属性サブタイプが存在する場合は、それに基づいて追加されたカスタム編集ボタンで構成されます。
タグ編集メタデータは、tag-edit-uri タグを使用して tlei ファイルで指定される .tagedit ファイル内で指定されます。
<tlei> <tag name="myTag"> <tag-edit-uri>tagedit/myTag.tagedit</tag-edit-uri> </tag> </tlei>
.tagedit ファイルの例を以下に示します。
<tag-edit> <dialog-info kind="insert-modify"> <field-group> <field name="value"> <display-name>Value</display-name> <bind-info source-kind="any"/> </field> <field name="converter"> <display-name>Converter</display-name> </field> </field-group> <field-group> <label>CSS Properties</label> <field name="styleClass"> <display-name>CSS Class</display-name> </field> <field name="style"> <display-name>CSS Style</display-name> </field> </field-group> </dialog-info> </tag-edit>
以下で、主要なタグについて説明します。
必要に応じて、それぞれ異なった kind 属性を持つ複数の dialog-info タグを使用できます。
format tlei タグを使用すると、ソース コード内でタグがどのようにフォーマットされるかを制御できます。
例を示します。
<tlei> <tag name="myTag"> <format line-break="before-after" content-format="wrap-indent"/> </tag> </tlei>
line-break 属性と content-format 属性は、両方とも必須です。
line-break 属性に使用可能な値は次のとおりです。
content-format 属性に使用可能な値は次のとおりです。
以下の tlei タグは、[デザイン パレット] ビューでタグがどのように表示されるかのカスタマイズに使用できます。
例を示します。
<tlei> <display-name>My Tag Library</display-name> <description>The description of the tag library.</description> <tag name="myTag"> <display-name>My Tag</display-name> <description>The description of my tag.</description> <small-icon>images/myTag.gif</small-icon> </tag> </tlei>
タグ ライブラリに JSF コンポーネントが格納されていることが分かっていると、たとえば属性値について JSF 式おおびメソッド バインディングを有効化するかどうかを判断する際に、非常に役立ちます。
タグ ライブラリに JSF コンポーネントが格納されていることを指定するには、
<tlei> <property name="jsf" value="true"/> </tlei>