All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.liftweb.http.StatefulSnippet.scala Maven / Gradle / Ivy

The newest version!
/*
 * 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 scala.xml.{NodeSeq, Elem}

/**
 * The same StatefulSnippet instance is used across a given page rendering.
 * 
* 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. *
* 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. *
 * 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
 *
 * }
 * 
*/ trait StatefulSnippet extends DispatchSnippet { private[this] var _names: Set[String] = Set() def addName(name: String): Unit = { 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 * * @param to - the target * @param func - the function to invoke when the link is clicked * @param body - the NodeSeq to wrap in the anchor tag * @param 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)).apply(res) } else if (isForm) { toMerge ++ res } else { res } } } /** * Mix this into a StatefulSnippet if you want a defined render method. */ trait RenderDispatch { /** * The predefined 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 predefined 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 } /** * This trait indicates if the snippet instance should be kept around for the duration of * the Request. There are cases when you don't want a snippet to be kept around. */ trait TransientSnippet { /** * Calculate if this snippet should be treated as transiet. */ def transient_? = true } /** * The companion object to the TransientSnippet trait */ object TransientSnippet { /** * Compute if the instance should be treated as transient */ def notTransient(obj: Any): Boolean = obj match { case t: TransientSnippet => !t.transient_? case _ => true } } /** * 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 an empty NodeSeq. */ trait BlankStatelessBehavior extends StatelessBehavior { def statelessDispatch: PartialFunction[String, NodeSeq => NodeSeq] = { case _ => _ => NodeSeq.Empty } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy