Liftでdate_select系ヘルパーを作る

Liftに日付入力SELECTを生成するヘルパーが無かったので、作ってみました。Lift1.1-M8です。そんなにうまくできてるわけではありませんが、困ってる人いたら参考にしてみてください。

DateSelect

import _root_.net.liftweb.http._
import _root_.net.liftweb.util._
import _root_.net.liftweb.common._
import _root_.scala.xml._

import _root_.java.text.SimpleDateFormat
import _root_.java.util.{Date,Calendar,GregorianCalendar}
import _root_.java.lang.Integer.parseInt //メソッド毎importできる

object DateSelect {

  def apply(vars: AnyVar[String,_],name:String) = new DateSelect(vars,name)

  val dummyYMD = "1970/01/01"
  private val formatterYMD = new SimpleDateFormat("yyyy/MM/dd")
  def parseYMD(ymd:String):Date
     = synchronized{ formatterYMD.parse(ymd) }
  def formatYMD(date:Date):String
     = synchronized{ formatterYMD.format(date) }
  def YMD2Calendar(ymd:String) = {
    val cal = new GregorianCalendar
    cal.setTime(DateSelect.parseYMD(ymd))
    cal
  }
  def splitYMD(ymd:String):(String,String,String) = {
    val cal = YMD2Calendar(ymd)
    val y = cal.get(Calendar.YEAR).toString
    val m = (cal.get(Calendar.MONTH)+1).toString
    val d = cal.get(Calendar.DATE).toString
    (y,m,d)
  }

  def toOpts(from:Int,to:Int,by:Int):Seq[(String,String)] =
    (from to to by by).map( i => i.toString -> i.toString )
  def toOpts(from:Int,to:Int):Seq[(String,String)] = toOpts(from,to,1)

  def toDate(y:String,m:String,d:String)
  = new GregorianCalendar(parseInt(y),parseInt(m)-1,parseInt(d)).getTime
}

class DateSelect(vars:AnyVar[String,_],name:String) {

  def currentYMD = if( vars.is == DateSelect.dummyYMD ){
    DateSelect.formatYMD(new Date)
  } else vars.is

  def date_html(attrs: (String, String)*): NodeSeq = {

    //SELECTパラメータを受け取って組み立て、
    //RequestVarへ入れるコールバック
    //hidden要素にバインドする。
    val callback = (s:String) => {
      val passedDate = DateSelect.toDate(
        S.param(name+"_y").open_!,
        S.param(name+"_m").open_!,
        S.param(name+"_d").open_! )
      vars( DateSelect.formatYMD( passedDate ) )
    }

    val (y,m,d) = DateSelect.splitYMD(currentYMD)

    SHtml.hidden( callback, currentYMD ) ++
    SHtml.select( DateSelect.toOpts(2009, 2011), Full(y), null,
    attrs ++ Seq(("name",name+"_y")): _*) ++
    SHtml.select( DateSelect.toOpts(1, 12), Full(m), null,
    attrs ++ Seq(("name",name+"_m")): _*) ++
    SHtml.select( DateSelect.toOpts(1, 31), Full(d), null,
    attrs ++ Seq(("name",name+"_d")): _*)
  }
}

使い方

class ASnippet {

  object startTime extends RequestVar[String](DateSelect.dummyYMD)
  object endTime extends RequestVar[String](DateSelect.dummyYMD)

  def addForm(xhtml: NodeSeq):NodeSeq = {

    def doAdd(){
      println("---startTime:" + startTime)
      println("---endTime:" + endTime)
    }

    bind("e", xhtml,
      "startTime" -> DateSelect(startTime,"startTime").date_html(),
      "endTime" -> DateSelect(endTime,"endTime").date_html(),
      "submit" -> SHtml.submit("送信", doAdd) )
  }
}

特に難しいことはやってないですが、ポイントは、

・HIDDEN要素に、サーバサイドコールバックのトリガーを持たせる。
・SELECT要素は文字列の運搬だけを行う。name属性は上書き。
・RequestVarでもSessionVarでも使えるようにAnyVarを使う。

※値を入力できるSHtml.hiddenはLift1.0では使えないので、何か別の方法考える必要あります。


要点だけ絞ったコードを貼りました(コピペで使えるはずです)が、時間も設定できるようにするにはパターンを増やすだけ。完成品ができたら後でgistにでも貼っておきます。


DATE SELECTがないことに今頃気づいて「げげぇっ」って感じで、自分も困ってる人なので、他に良案・良実装があれば教えていただければ幸いです。


コメント

コメントしてください
お名前:
入力しなければ「匿名さん」。20字以内。

メール:
入力しても表示しません

URL:
入力すればリンクが貼れます


コメント: