Snippetからの出力内容
リスト1のSnippetタグは、内部にHTMLタグやXMLタグを含んでいるのが分かると思います。Snippet内部に含まれているタグは、scala.xml.NodeSeqオブジェクトとして、Snippetの関数に引数で渡されます。form="POST"と指定することで、Snippetが出力した内容がformタグで囲まれます。
リスト1の*2、*3は、Snippet実行時に、動的に置き換える部分です。net.liftweb.util.Helpersオブジェクトのbind関数で、指定した名前空間のタグの内容を動的に置き換えることができます。bind関数については、本項の後半で説明しますので、今の段階では、Snippetタグ内部にある、任意の名前空間のタグは動的に置き換えることができる部分であるという理解でかまいません。
レイアウトの分離
テンプレートには、ヘッダーやフッターなどを分割してレイアウトを分離する機能があります。mavenで生成したプロジェクトでは、最初からプロジェクトディレクトリ以下の「src/main/webApp/template-hidden」ディレクトリに、default.htmlというファイル名で、デフォルトのヘッダーやフッターを含むXHTMLファイルが配置されています。
リスト1の*4で、ビルトインSnippetである<lift:surround with="default" at="content"> タグを利用して、レイアウトを指定しています。with="default"はレイアウト名の指定です。指定するレイアウト名は、「src/main/webApp/template-hidden」ディレクトリにあるhtmlファイル名になります。レイアウト名として"default"を指定しているので、レイアウトに利用されるファイルはdefault.htmlです。at="content"はレイアウト内に内容を挿入する位置を指定しています。挿入する位置は、レイアウト用htmlファイル内に、<lift:bind name="挿入する位置の名前">タグで指定されている名前になります。
リスト2は、デフォルトで生成されるdefault.htmlの内容の一部です。*1の<lift:bind name="content" />の部分が、リスト1の<lift:surround>タグの内容に置き換えられます。
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:lift="http://liftweb.net/">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<title>Lift Web Framework</title>
<lift:CSS.blueprint />
<lift:CSS.fancyType />
<script id="jquery" src="/classpath/jquery.js" type="text/javascript"/>
<script id="json" src="/classpath/json.js" type="text/javascript"/>
...省略
</head>
<body>
<div class="container">
...省略
<!-- SiteMapに登録されているMenuに従ってメニュー生成 -->
<div class="column span-6 colborder sidebar">
<hr class="space" />
<!-- SiteMapに設定されている内容からメニュー用リンクを生成するSnippet -->
<lift:Menu.builder />
<div>
<!-- エラーメッセージが設定されている場合に表示するビルトインSnippet -->
<lift:snippet type="msgs"/>
<hr class="space" />
</div>
</div>
<div class="column span-17 last">
<!-- この部分が置き換えられる -->
<lift:bind name="content" /> *1
</div>
...省略
</div>
</body>
</html>
ビルトインSnippet
Liftに標準で組み込まれているビルトインSnippetは、代表的なものとして以下のSnippetが用意されています。
| Snippet | 説明 | 例 |
lift:Surround |
このタグが含む内容を、with属性で指定されたレイアウトファイル内へ、at属性で指定した位置に挿入します。 |
<lift:surround with="template_name">children</lift:surround> |
lift:bind-at |
lift:Surroundタグ内で利用します。lift:Surroundタグでat属性を指定しない場合、このタグの内容がname属性で指定した位置に挿入されます。lift:Surroundタグ内で、ヘッダー部分とコンテンツ本文の2か所をレイアウトに挿入したい場合などは、このタグでそれぞれ挿入したい内容を囲みます。 |
<lift:surround with="default" ><lift:bind-at name="header">ヘッダー内容</lift:bind-at> <lift:bind-at name="contents">コンテンツ本文 </lift:bind-at></lift:surround> |
lift:bind |
lift:Surroundタグで指定されるレイアウトファイル内で使用し、内容を挿入する位置を設定します。 |
<lift:bind name="content" /> |
lift:Loc |
このタグのname属性を元に、Boot.scalaで設定されているSiteMapの名前からリンクを作成します。 |
<lift:Loc name="menu_name" /> |
lift:Embed |
他のテンプレートを指定して取り込むことができます。 | <lift:embed what="other_template" /> |
lift:Ignore |
このタグの内容は、Liftがテンプレートをレンダリングする際に無視されます。 | <lift:ignore>この部分は無視</lift:ignore> |
lift:Children |
このタグで囲んだ内容をグルーピングできます。ajaxでHTMLの一部を返す際などに、XMLとして複数のタグをまとめる際に利用されます。 | <lift:children><div>This is the first DIV</div> <div>This is the other DIV</div></lift:children> |
Snippet
テンプレートのレンダリングの過程で、SnippetタグはSnippetクラスの関数を呼び出した結果に置き換えられます。
Snippetは、Scalaのクラスとして、snippetパッケージ内に作成します。アプリケーションのパッケージ名が、「demo.greeting」の場合、Snippetクラスは「demo.greeting.snippet」パッケージに配置されている必要があります。Snippetとして作成するクラス名は、任意の名前を使用してかまいません。
リスト3は、Snippetの例です。
// snippetパッケージに作成する
package demo.greeting.snippet
// クラス名は任意
class SampleSnipet {
// 関数名は任意。引数にscala.xml.NodeSeqを受け取り、
// 戻り値としてscala.xml.NodeSeqを返す
def hello( xhtml:NodeSeq ):NodeSeq = {
// User.currentUserで現在ログインしているユーザーを取得。
// パターンマッチを利用して、ログインしていない場合は"Guest"を設定している
var name = User.currentUser match {
case Full(user) => user.shortName
case _ => "Guest"
}
// bind関数を利用して、引数のXHTML内で<greeting:...>で始まるタグの
// 内容を置き換える
bind( "greeting", *1
xhtml,
"name" -> SHtml.text( name, name=_ ), // テキストフィールドを生成 *2
"submit" -> SHtml.submit( "Say hello", greeting ) // submitボタンを生成 *3
)
}
}
Snippet関数は、引数にscala.xml.NodeSeqオブジェクトを受け取るように定義されていなければなりません。引数として渡されるNodeSeqオブジェクトは、テンプレートの中で該当するSnippetタグの中に含まれているXMLになります。引数で渡されたXMLを加工することで、テンプレートの内容に依存しない出力を生成することが可能です。Snippet関数は、出力としてテンプレートに埋め込む内容も、引数と同じくscala.xml.NodeSeqオブジェクトを返す必要があります。
Snippet内で使用されているbind関数は、Snippet関数の引数に渡されたXHTMLの中で、特定の名前のタグの内容を置き換える関数です。例では、テンプレートファイル内に、「<greeting:name/>」と記述されている部分をテキストフィールドに、「<greeting:submit/>」と記述されている部分はsubmitボタンへと置き換えて出力されます。このbind関数を利用することで、Snippetの中にはHTMLタグを含まずに、かつテンプレートの内容に応じた出力を生成することができ、デザインと表示ロジックを完全に分離することが可能となっています。
SHtml.text関数やSHtml.submit関数は、HTMLタグを生成するヘルパー関数です。SHtmlオブジェクトには、リンクやチェックボックスなどの各種のHTMLタグを生成する関数が多数用意されています。どのような関数があるかについては、本稿の後半にて紹介します。
