目次

Version 5, last updated by mads379 at Nov 29 21:54 UTC

CSS セレクタによるバインディング

Lift 2.2-M1 では、XHTML を変換するための新しいしくみとして、CSS セレクタトランスフォーム (CssBindFunc) が導入されました。CSS セレクタトランスフォームに用意された CSS セレクタのサブセットを使うと、NodeSeq => NodeSeq の変換を行うことができます。次に例を示します。

  • “#name” #> userName // id が name の要素を変数 userName で置き換えます。
  • “#chat_lines *” #> listOfChats // chat_lines の内容を listOfChats の各要素で置き換えます。
  • “.pretty *” #> <b>Unicorn</b>// CSS クラス pretty の各要素の内容を <b>Unicorn</b> で置き換えます。
  • “dog=cat [href]” #> “http://dogscape.com” // dog 属性を持つすべての要素の href 属性に cat を設定します。
  • “#name” #>userName&“#age” #>userAge // name に userName を設定し、age に userAge を設定します。

CSS セレクタトランスフォームは NodeSeq => NodeSeq を継承します。CSS セレクタトランスフォームは、ほぼ文字どおりの処理を行う関数で、NodeSeq =>NodeSeq を期待するあらゆるものに引数として渡したり、NodeSeq => NodeSeq を返す任意のメソッドの結果として返すことができます。

実際にどのように動作するのか、以下で少し細かくみていきましょう。

まず、import net.liftweb.util._ および import Helpers._ を記述する必要があります。これらのパッケージには、CSS セレクタトランスフォームを動作させるためのクラスと暗黙の型変換が含まれています。

CSS セレクタトランスフォームは次のように定義されます: セレクタを表す String #> トランスフォーム値。

セレクタは、CSS セレクタの次のサブセットを実装する String 定数です。

  • #id – 指定された id を持つ要素を選択します。
  • .class – 空白で区切られた値のいずれかが class に等しい class 属性を持つすべての要素を選択します。
  • attr_name=attr_value – 指定された属性が指定された値に等しいすべての要素を選択します。

セレクタの後には置き換えの規則を記述できます。

  • なし (たとえば “#id”)。一致するすべての要素を、指定された値で置き換えます。
    “#name” #>"David" //<span><span id="name"/></span>-><span>David</span>
  • * (たとえば “#id *”)。一致する要素の内容の子を、指定された値で置き換えます。
    “#name *” #>"David" //<span><span id="name"/></span>-><span><span id="name>David</span></span>
  • [attr] (たとえば “#id [href]”)。一致する属性の値を、指定された値で置き換えます (class 属性の場合には、指定された値が要素の class 属性に追記されることに注意してください)。
    “#link [href]” #>"http://dogscape.com" //<a href="#" id="link">Dogscape</a>-><a href="http://dogscape.com" id="link">Dogscape</a>

CSS セレクタトランスフォームの左側の部分に指定できるのは、次のうちのいずれか 1 つです。

  • String – String 定数:
    “#name *” #>"David" //<span id="name"/>-><span id="name">David</span>
    “#name *” #>getUserNameAsString
  • NodeSeq – NodeSeq 定数:
    “#name *” #><i>David</i>//<span id="name"/>-><span id="name"><i>David</i></span>
    “#name *” #>getUserNameAsHtml
  • NodeSeq =>NodeSeq — ノードを変換する関数 (CssBindFunc も指定できます):
    “#name” #> (n: NodeSeq) => n (“class” -> “dog”) // <span id="name"/> – ><span id="name" class="dog"/>
  • Bindable – Bindable トレイトを実装する何か (たとえば MappedField や Record.Field など)
  • StringPromotable — String に上位変換可能な定数 (Int、Symbol、Long、または Boolean)。Int、Symbol、Long、または Boolean から StringPromotable への自動的な (暗黙の) 型変換があります。
    “#id_like_cats” #>true
    “#number_of_cats” #>2
  • IterableConst – String、NodeSeq、または Bindable の Box、Seq、あるいは Option。暗黙の型変換は、Box[String]、List[String]、List[NodeSeq] などを自動的に IterableConst に上位変換します。
    “#id” #>(Empty: Box[String]) //<span><span id="id">Hi</span></span>-><span/>
    “#id” #>List(“a”, “b”, “c”) //<span><span id="id"/></span>-><span>abc</span>
    “#id [href]” #>(None: Option[String])<a id="id" href="dog"/>-><a id="id"/>

選択された要素の子に対してバインドする場合には、IterableConst へのバインドによって、該当する要素の複数のコピーが生成されます (該当する要素が id 属性を持つ場合、その id 属性は最初の要素の後では省かれます):

“#line *” #>List(“a”, “b”, “c”) //<li id="line>sample</li>-><li id="line">a</li><li>b</li><li>c</li>
"#age *" #>(None: Option[NodeSeq]) //<span><span id="age">Dunno</span></span>-><span/>

上の使用例は少々奇異に (ほとんど直交性がないため) 見えるかもしれませんが、Lift ではよくある使用例です。

  • IterableFunc — NodeSeq を String、NodeSeq、Seq[String]、Seq[NodeSeq]、Box[String]、Box[NodeSeq]、Option[String]、または Option[NodeSeq] に変換する関数の Box、Seq、または Option。

IterableFunc にも、IterableConst で複数の値を扱う場合と同様の規則が適用されます。暗黙の型変換は、該当するシグニチャを持つ関数を自動的にIterableFunc に上位変換します。

CSS セレクタトランスフォームは & メソッドでチェインすることができます。

“#id” #>"33"&“#name” #>"David"&“#chat_line” #>List(“a”, “b”, “c”)&ClearClearable

CSS セレクタトランスフォームは、Lift の従来のバインディング (Helpers.bind() を参照) の代替手段を提供します。