alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Lift Framework example source code file (StatefulSnippet.scala)

This example Lift Framework source code file (StatefulSnippet.scala) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Lift Framework tags/keywords

dispatchit, dispatchsnippet, map, nodeseq, nodeseq, partialfunction, partialfunction, renderfuncdispatch, set, set, statefulsnippet, statelessbehavior, string, string

The Lift Framework StatefulSnippet.scala source code

/*
 * Copyright 2007-2011 WorldWide Conferencing, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.liftweb
package http

import net.liftweb.common._
import net.liftweb._
import util._
import Helpers._
import xml.{Text, NodeSeq, Elem}

/**
 * The same StatefulSnippet instance is used across a given page rendering.
 * <br/>
 * If the StatefulSnippet is used to render a form, a hidden field is added to
 * the form that causes the same instance to be used on the page that is the
 * target of the form submission.
 * <br/>
 * If you want to keep the same snippet for a page rendered via a link (<a
 * href...>) use the StatefulSnippet.link method to create the link.  This will
 * cause the registerThisSnippet method to be called and the same instance will
 * be used on the target page.
 * <pre>
 * class CountGame extends StatefulSnippet  {
 *  val dispatch: DispatchIt =  {
 *    case "run" => run _
 * }
 *
 *  def run(xhtml: NodeSeq): NodeSeq =  {
 *    if (lastGuess == number)  {
 *      bind("count", chooseTemplate("choose", "win", xhtml), "number" --> number, "count" --> count)
 * } else  {
 *      bind("count", chooseTemplate("choose", "guess", xhtml),
 *        "input" --> text("", guess _),
 *        "last" --> lastGuess.map(v => if (v < number) v+" is low" else v+"is high").openOr("Make first Guess")
 *      )
 * }
 *
 *  private def guess(in: String)  {
 *    count += 1
 *    lastGuess = Full(toInt(in))
 * }
 *
 *  private val number = 1 + randomInt(100)
 *  private var lastGuess: Box[Int] = Empty
 *  private var count = 0
 *
 * }
 * </pre>
 */
trait StatefulSnippet extends DispatchSnippet {
  private[this] var _names: Set[String] = Set()
  def addName(name: String) {
    synchronized {
      _names = _names + name
    }
  }

  def names: Set[String] = synchronized {
    _names
  }

  def registerThisSnippet() = names.foreach(n => S.overrideSnippetForClass(n, this))

  def unregisterThisSnippet() =  names.foreach(n => S.unsetSnippetForClass(n))

  /**
   * create an anchor tag around a body
   *
   * @to - the target
   * @param func - the function to invoke when the link is clicked
   * @param body - the NodeSeq to wrap in the anchor tag
   * @attrs - the (optional) attributes for the HTML element
   */
  def link(to: String, func: () => Any, body: NodeSeq, attrs: SHtml.ElemAttr*): Elem =
    SHtml.link(to, () => { registerThisSnippet(); func() }, body, attrs: _*)

  /**
   * Redirect to another page, but make sure this StatefulSnippet is registered
   * on that page so the state continues on the new page
   */
  def redirectTo(where: String): Nothing = S.redirectTo(where, registerThisSnippet)

  /**
   * See Other to another page, but make sure this StatefulSnippet is registered
   * on that page so the state continues on the new page
   */
  def seeOther(where: String): Nothing = S.seeOther(where, registerThisSnippet)

  /**
   * Merge the SHtml into the form
   */
  private[http] def mergeIntoForm(isForm: Boolean, res: NodeSeq, toMerge: => NodeSeq): NodeSeq = {
    val formElem = Helpers.findOption(res){
      case e: Elem if e.label == "form" && null == e.prefix=> Some(e)
      case _ => None
    }

    if (formElem.isDefined) {
      import util.Helpers._

      ("form *" #> ((kids: NodeSeq) => toMerge ++ kids))(res)
    } else if (isForm) {
      toMerge ++ res
    } else {
      res
    }
  }

}

/**
 * Mix this into a StatefulSnippet if you want a defined render method.
 */
trait RenderDispatch {
  /**
   * The pre-defined dispatch
   */
  def dispatch: PartialFunction[String, NodeSeq => NodeSeq] = Map("render" -> render _)

  /**
   * You have to define this method
   */
  def render(in: NodeSeq): NodeSeq

}

/**
 * Mix this into a StatefulSnippet if you want a defined render method.  Differs
 * from RenderDispatch because the render method returns a NodeSeq => NodeSeq
 */
trait RenderFuncDispatch {
  /**
   * The pre-defined dispatch
   */
  def dispatch: PartialFunction[String, NodeSeq => NodeSeq] = Map("render" -> render)

  /**
   * You have to define this method
   */
  def render: NodeSeq => NodeSeq
}

/**
 * The simple composition of StatefulSnippet, Whence and RenderFuncDispatch.
 * This is the common use of stateful snippets and makes things easier.
 */
trait SimpleStateful extends StatefulSnippet with Whence with RenderFuncDispatch

trait DispatchSnippet {
  type DispatchIt = PartialFunction[String, NodeSeq => NodeSeq]

  def dispatch: DispatchIt
}

/**
 * Mix this snippet into any snippet.  If the snippet is invoked in response to a
 * stateless request, then the behavior method is called with the method name of
 * the snippet (usually render, but there may be others if you specify a method
 * after the snippet name: MySnippet.dothing).
 */
trait StatelessBehavior {
  /**
   * Given the method name, return the transformation for the method
   */
  def statelessDispatch: PartialFunction[String, NodeSeq => NodeSeq]
}

/**
 * A simpler way to define behavior if the snippet is invoked.  Just implement the stateless method
 * and all methods for the snippet will use that behavior.
 */
trait SimpleStatelessBehavior extends StatelessBehavior {
  def stateless: NodeSeq => NodeSeq
  def statelessDispatch: PartialFunction[String, NodeSeq => NodeSeq] = {
    case _ => stateless
  }
}

/**
 * A "default" implementation of StatelessBehavior.  Just ignore everything and return a zero-length Text.
 */
trait BlankStatelessBehavior extends StatelessBehavior {
  def statelessDispatch: PartialFunction[String, NodeSeq => NodeSeq] = {
    case _ => _ => NodeSeq.Empty
  }
}

Other Lift Framework examples (source code examples)

Here is a short list of links related to this Lift Framework StatefulSnippet.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.