Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adresses 980 and 1164 and some other miscelaneous stuff

  • Loading branch information...
commit b971277ebd726ac30d4ab29fb38a09a6f7b5dc15 1 parent 865fc7d
@dpp dpp authored
View
25 core/util/src/main/scala/net/liftweb/util/BindHelpers.scala
@@ -695,16 +695,6 @@ trait BindHelpers {
*/
def stripHead(in: NodeSeq): NodeSeq = {
("head" #> ((ns: NodeSeq) => ns.asInstanceOf[Elem].child))(in)
- import scala.xml.transform._
-
- val rewrite = new RewriteRule {
- override def transform(in: Node): Seq[Node] = in match {
- case e: Elem if e.label == "head" && (e.namespace eq null) => this.transform(e.child)
- case x => x
- }
- }
-
- (new RuleTransformer(rewrite)).transform(in)
}
/**
@@ -713,21 +703,6 @@ trait BindHelpers {
*/
def replaceIdNode(in: NodeSeq, id: String, replacement: NodeSeq): NodeSeq = {
(("#"+id) #> replacement)(in)
- /*
- import scala.xml.transform._
-
- val cmp = Some(Text(id))
-
- val rewrite = new RewriteRule {
- override def transform(in: Node): Seq[Node] = in match {
- case e: Elem if e.attribute("id") == cmp => replacement
-
- case x => x
- }
- }
-
- (new RuleTransformer(rewrite)).transform(in)
- */
}
/**
View
10 project/build.properties
@@ -1,7 +1,9 @@
-#Project properties
-project.organization=net.liftweb
+#
+#Fri Jan 27 12:14:38 PST 2012
project.name=lift-framework
-sbt.version=0.7.7
+project.organization=net.liftweb
project.version=2.5-SNAPSHOT
-build.scala.versions=2.8.2 2.8.1 2.8.0 2.9.1 2.9.0-1 2.9.0
+sbt.version=0.7.7
+def.scala.version=2.7.7
+build.scala.versions=2.9.1 2.8.2 2.8.1 2.8.0 2.9.0-1 2.9.0
project.initialize=false
View
351 web/webkit/src/main/scala/net/liftweb/http/CometActor.scala
@@ -38,7 +38,9 @@ import java.util.Locale
* and resurects the actor.
*/
object ActorWatcher extends scala.actors.Actor with Loggable {
+
import scala.actors.Actor._
+
def act = loop {
react {
case scala.actors.Exit(actor: scala.actors.Actor, why: Throwable) =>
@@ -62,7 +64,7 @@ object ActorWatcher extends scala.actors.Actor with Loggable {
* actor to this List
*/
@volatile var failureFuncs: List[(scala.actors.Actor, Throwable) => Unit] = logActorFailure _ ::
- startAgain _ :: Nil
+ startAgain _ :: Nil
this.trapExit = true
this.start
@@ -90,9 +92,8 @@ MyType <: CometState[DeltaType, MyType]] {
trait CometStateWithUpdate[UpdateType, DeltaType <: DeltaTrait,
MyType <: CometStateWithUpdate[UpdateType,
- DeltaType, MyType]]
- extends CometState[DeltaType, MyType]
-{
+ DeltaType, MyType]]
+ extends CometState[DeltaType, MyType] {
self: MyType =>
def process(in: UpdateType): MyType
}
@@ -127,11 +128,13 @@ trait StatefulComet extends CometActor {
case v if testState(v).isDefined =>
testState(v).foreach {
ns =>
- if (ns ne state) {
- val diff = ns - state
- state = ns
- partialUpdate(setupLocalState {diff.map(_.toJs).foldLeft(Noop)(_ & _)})
- }
+ if (ns ne state) {
+ val diff = ns - state
+ state = ns
+ partialUpdate(setupLocalState {
+ diff.map(_.toJs).foldLeft(Noop)(_ & _)
+ })
+ }
}
}
@@ -147,7 +150,9 @@ trait StatefulComet extends CometActor {
object CurrentCometActor extends ThreadGlobal[LiftCometActor]
object AddAListener {
- def apply(who: SimpleActor[Any]) = new AddAListener(who, { case _ => true } )
+ def apply(who: SimpleActor[Any]) = new AddAListener(who, {
+ case _ => true
+ })
}
/**
@@ -191,23 +196,23 @@ object ListenerManager {
*
* <pre name="code" class="scala">
* case object Tick
- *
+ *
* object Ticker extends ListenerManager {
* import net.liftweb.util.ActorPing
- *
+ *
* // Set up the initial tick
* ActorPing.schedule(this, Tick, 1000L)
*
* // This is a placeholder, since we're only interested
* // in Ticks
* def createUpdate = "Registered"
- *
+ *
* override def mediumPriority = {
* case Tick => {
* updateListeneres(Tick)
* ActorPing.schedule(this, Tick, 1000L)
- * }
- * }
+ * }
+ * }
* }
* </pre>
*
@@ -222,7 +227,7 @@ object ListenerManager {
* </pre>
*
* @see CometListener
- *
+ *
*/
trait ListenerManager {
self: SimpleActor[Any] =>
@@ -236,21 +241,20 @@ trait ListenerManager {
protected def messageHandler: PartialFunction[Any, Unit] =
highPriority orElse mediumPriority orElse
- listenerService orElse lowPriority
-
- protected def listenerService: PartialFunction[Any, Unit] =
- {
- case AddAListener(who, shouldUpdate) =>
- val pair = (who, shouldUpdate)
- listeners ::= pair
- updateIfPassesTest(createUpdate)(pair)
-
- case RemoveAListener(who) =>
- listeners = listeners.filter(_._1 ne who)
- if (listeners.isEmpty) {
- onListenersListEmptied()
- }
- }
+ listenerService orElse lowPriority
+
+ protected def listenerService: PartialFunction[Any, Unit] = {
+ case AddAListener(who, shouldUpdate) =>
+ val pair = (who, shouldUpdate)
+ listeners ::= pair
+ updateIfPassesTest(createUpdate)(pair)
+
+ case RemoveAListener(who) =>
+ listeners = listeners.filter(_._1 ne who)
+ if (listeners.isEmpty) {
+ onListenersListEmptied()
+ }
+ }
/**
* Called after RemoveAListener-message is processed and no more listeners exist.
@@ -336,9 +340,9 @@ trait CometListenee extends CometListener {
* to get a Java-useable LiftActorJ with ListenerManager
*/
abstract class LiftActorJWithListenerManager extends LiftActorJ with ListenerManager {
- protected override def messageHandler: PartialFunction[Any, Unit] =
- highPriority orElse mediumPriority orElse
- listenerService orElse lowPriority orElse _messageHandler
+ protected override def messageHandler: PartialFunction[Any, Unit] =
+ highPriority orElse mediumPriority orElse
+ listenerService orElse lowPriority orElse _messageHandler
}
/**
@@ -369,7 +373,9 @@ trait CometListener extends CometActor {
* in the partial function that handles the message.
*/
@deprecated("Accept/reject logic should be done in the partial function that handles the message.")
- protected def shouldUpdate: PartialFunction[Any, Boolean] = { case _ => true}
+ protected def shouldUpdate: PartialFunction[Any, Boolean] = {
+ case _ => true
+ }
abstract override protected def localSetup() {
registerWith ! AddAListener(this, shouldUpdate)
@@ -414,7 +420,7 @@ trait LiftCometActor extends TypedActor[Any, Any] with ForwardableActor[Any, Any
* <pre>
* override def cometTimeoutHandler(): JsCmd = {
* Alert("Timeout processing comet-request, timeout is: " + cometProcessingTimeout + "ms")
- * }
+ * }
* </pre>
*/
def cometProcessingTimeoutHandler(): JsCmd = Noop
@@ -430,7 +436,7 @@ trait LiftCometActor extends TypedActor[Any, Any] with ForwardableActor[Any, Any
* <pre>
* override def renderTimeoutHandler(): Box[NodeSeq] = {
* Full(&lt;div&gt;Comet {this.getClass} timed out, timeout is {cometRenderTimeout}ms&lt;/div&gt;)
- * }
+ * }
* </pre>
*/
def cometRenderTimeoutHandler(): Box[NodeSeq] = Empty
@@ -478,15 +484,18 @@ trait LiftCometActor extends TypedActor[Any, Any] with ForwardableActor[Any, Any
/**
* If the predicate cell changes, the Dependent will be notified
*/
- def predicateChanged(which: Cell[_]): Unit = {poke()}
+ def predicateChanged(which: Cell[_]): Unit = {
+ poke()
+ }
/**
* The locale for the session that created the CometActor
*/
def cometActorLocale: Locale = _myLocale
+
private var _myLocale = Locale.getDefault()
-
+
private[http] def setCometActorLocale(loc: Locale) {
_myLocale = loc
}
@@ -528,7 +537,7 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
/**
* The last rendering (cached or not)
*/
- private def lastRendering: RenderOut =
+ private def lastRendering: RenderOut =
if (dontCacheRendering) {
val ret = (render ++ jsonInCode): RenderOut
theSession.updateFunctionMap(S.functionMap, spanId, lastRenderTime)
@@ -545,7 +554,7 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
_realLastRendering = last
}
}
-
+
private var wasLastFullRender = false
@transient
private var listeners: List[(ListenerId, AnswerRender => Unit)] = Nil
@@ -620,7 +629,7 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
attributes: Map[String, String]) {
if (!dontCacheRendering) {
lastRendering = RenderOut(Full(defaultHtml),
- Empty, Empty, Empty, false)
+ Empty, Empty, Empty, false)
}
this._theType = theType
@@ -686,31 +695,31 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
def onJsonError: Box[JsCmd] = Empty
lazy val (jsonCall, jsonInCode) = S.buildJsonFunc(Full(_defaultPrefix), onJsonError, _handleJson)
-
+
/**
- * Override this method to deal with JSON sent from the browser via the sendJson function. This
- * is based on the Lift JSON package rather than the handleJson stuff based on the older util.JsonParser. This
- * is the prefered mechanism. If you use the jsonSend call, you will get a JObject(JField("command", cmd), JField("param", params))
- */
+ * Override this method to deal with JSON sent from the browser via the sendJson function. This
+ * is based on the Lift JSON package rather than the handleJson stuff based on the older util.JsonParser. This
+ * is the prefered mechanism. If you use the jsonSend call, you will get a JObject(JField("command", cmd), JField("param", params))
+ */
def receiveJson: PartialFunction[JsonAST.JValue, JsCmd] = Map()
/**
- * The JavaScript call that you use to send the data to the server. For example:
- * &lt;button onclick={jsonSend("Hello", JsRaw("Dude".encJs))}&gt;Click&lt;/button&gt;
- */
+ * The JavaScript call that you use to send the data to the server. For example:
+ * &lt;button onclick={jsonSend("Hello", JsRaw("Dude".encJs))}&gt;Click&lt;/button&gt;
+ */
def jsonSend: JsonCall = _sendJson
/**
- * The call that packages up the JSON and tosses it to the server. If you set autoIncludeJsonCode to true,
- * then this will be included in the stuff sent to the server.
- */
+ * The call that packages up the JSON and tosses it to the server. If you set autoIncludeJsonCode to true,
+ * then this will be included in the stuff sent to the server.
+ */
def jsonToIncludeInCode: JsCmd = _jsonToIncludeCode
private lazy val (_sendJson, _jsonToIncludeCode) = S.createJsonFunc(Full(_defaultPrefix), onJsonError, receiveJson _)
/**
- * Set this method to true to have the Json call code included in the Comet output
- */
+ * Set this method to true to have the Json call code included in the Comet output
+ */
def autoIncludeJsonCode: Boolean = false
/**
@@ -718,14 +727,23 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
*/
def buildSpan(time: Long, xml: NodeSeq): NodeSeq = {
Elem(parentTag.prefix, parentTag.label, parentTag.attributes,
- parentTag.scope, Group(xml)) %
- new UnprefixedAttribute("id",
- Text(spanId),
- if (time > 0L) {
- new PrefixedAttribute("lift", "when",
- time.toString,
- Null)
- } else {Null})
+ parentTag.scope, Group(xml)) %
+ new UnprefixedAttribute("id",
+ Text(spanId),
+ if (time > 0L) {
+ new PrefixedAttribute("lift", "when",
+ time.toString,
+ Null)
+ } else {
+ Null
+ })
+ }
+
+ /**
+ * How to report an error that occurs during message dispatch
+ */
+ protected def reportError(msg: String, exception: Exception) {
+ logger.error(msg, exception)
}
protected override def messageHandler = {
@@ -736,29 +754,37 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
S.initIfUninitted(theSession) {
RenderVersion.doWith(uniqueId) {
S.functionLifespan(true) {
- what.apply(in)
+ try {
+ what.apply(in)
+ } catch {
+ case e: Exception => reportError("Message dispatch for " + in, e)
+ }
if (S.functionMap.size > 0) {
theSession.updateFunctionMap(S.functionMap,
- uniqueId, lastRenderTime)
+ uniqueId, lastRenderTime)
S.clearFunctionMap
}
}
}
}
}
-
+
def isDefinedAt(in: Any): Boolean =
CurrentCometActor.doWith(CometActor.this) {
S.initIfUninitted(theSession) {
RenderVersion.doWith(uniqueId) {
S.functionLifespan(true) {
- what.isDefinedAt(in)
+ try {
+ what.isDefinedAt(in)
+ } catch {
+ case e: Exception => reportError("Message test for " + in, e); false
+ }
}
}
}
}
}
-
+
myPf
}
@@ -773,7 +799,7 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
/**
* Calculate fixedRender and capture the postpage javascript
*/
- protected def calcFixedRender: Box[NodeSeq] =
+ protected def calcFixedRender: Box[NodeSeq] =
fixedRender.map(ns => theSession.postPageJavaScript() match {
case Nil => ns
case xs => {
@@ -785,7 +811,7 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
* We have to cache fixedRender and only change it if
* the tempalte changes or we get a reRender(true)
*/
- private def internalFixedRender: Box[NodeSeq] =
+ private def internalFixedRender: Box[NodeSeq] =
if (!cacheFixedRender) {
calcFixedRender
} else {
@@ -872,7 +898,7 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
*/
case UpdateDefaultXml(xml) => {
val redo = xml != _defaultHtml
-
+
_defaultHtml = xml
if (redo) {
@@ -884,15 +910,21 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
askingWho match {
case Full(who) => forwardMessageTo(AskRender, who) // forward AskRender
case _ => {
- if (!deltas.isEmpty || devMode) performReRender(false)
-
- reply(AnswerRender(new XmlOrJsCmd(spanId, lastRendering,
- buildSpan _, notices toList),
- whosAsking openOr this, lastRenderTime, true))
+ if (!deltas.isEmpty || devMode)
+ try {
+ performReRender(false)
+ } catch {
+ case e: Exception => reportError("Failed performReRender", e)
+ }
+
+ reply(AnswerRender(new XmlOrJsCmd(spanId, lastRendering,
+ buildSpan _, notices toList),
+ whosAsking openOr this, lastRenderTime, true))
clearNotices
}
}
+
case ActionMessageSet(msgs, req) =>
S.doCometParams(req.params) {
S.jsToAppend() match {
@@ -900,7 +932,16 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
case js => partialUpdate(js)
}
- reply(msgs.map(_()) ::: List(S.noticesToJsCmd))
+ val computed: List[Any] =
+ msgs.flatMap {
+ f => try {
+ List(f())
+ } catch {
+ case e: Exception => reportError("Ajax function dispatch", e); Nil
+ }
+ }
+
+ reply(computed ::: List(S.noticesToJsCmd))
}
case AskQuestion(what, who, otherlisteners) => {
@@ -929,7 +970,7 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
}
case ShutdownIfPastLifespan =>
- for{
+ for {
ls <- lifespan if listeners.isEmpty && (lastListenTime + ls.millis) < millis
} {
this ! ShutDown
@@ -961,12 +1002,12 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
deltas = (delta :: deltas).filter(d => (m - d.timestamp) < 120000L)
if (!listeners.isEmpty) {
val postPage = theSession.postPageJavaScript()
- val rendered =
+ val rendered =
AnswerRender(new XmlOrJsCmd(spanId, Empty, Empty,
- Full(cmd & postPage),
- Empty, buildSpan, false,
- notices toList),
- whosAsking openOr this, time, false)
+ Full(cmd & postPage),
+ Empty, buildSpan, false,
+ notices toList),
+ whosAsking openOr this, time, false)
clearNotices
listeners.foreach(_._2(rendered))
listeners = Nil
@@ -1019,7 +1060,9 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
* be sent to the client. It's a much better practice to use
* partialUpdate for non-trivial CometActor components.
*/
- def reRender() {reRender(false)}
+ def reRender() {
+ reRender(false)
+ }
/**
@@ -1074,8 +1117,8 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
theSession.updateFunctionMap(S.functionMap, spanId, lastRenderTime)
val rendered: AnswerRender =
- AnswerRender(new XmlOrJsCmd(spanId, lastRendering, buildSpan _, notices toList),
- this, lastRenderTime, sendAll)
+ AnswerRender(new XmlOrJsCmd(spanId, lastRendering, buildSpan _, notices toList),
+ this, lastRenderTime, sendAll)
clearNotices
listeners.foreach(_._2(rendered))
@@ -1107,13 +1150,15 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
this ! PartialUpdateMsg(() => cmd)
}
- protected def startQuestion(what: Any) {}
+ protected def startQuestion(what: Any) {
+ }
/**
* This method will be called after the Actor has started. Do any setup here.
* DO NOT do initialization in the constructor or in initCometActor... do it here.
*/
- protected def localSetup(): Unit = {}
+ protected def localSetup(): Unit = {
+ }
/**
* Comet Actors live outside the HTTP request/response cycle.
@@ -1125,7 +1170,8 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
* or capture any request parameters that you care about rather
* the keeping the whole Req reference.
*/
- protected def captureInitialReq(initialReq: Box[Req]) {}
+ protected def captureInitialReq(initialReq: Box[Req]) {
+ }
private def _localShutdown() {
localShutdown()
@@ -1142,7 +1188,8 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
/**
* This method will be called as part of the shut-down of the actor. Release any resources here.
*/
- protected def localShutdown(): Unit = {}
+ protected def localShutdown(): Unit = {
+ }
/**
* Compose the Message Handler function. By default,
@@ -1156,11 +1203,11 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
private def composeFunction_i: PartialFunction[Any, Unit] = {
// if we're no longer running don't pass messages to the other handlers
// just pass them to our handlers
- if (!_running && (millis - 20000L) > _shutDownAt)
+ if (!_running && (millis - 20000L) > _shutDownAt)
_mediumPriority orElse _lowPriority
- else
- highPriority orElse mediumPriority orElse
- _mediumPriority orElse lowPriority orElse _lowPriority
+ else
+ highPriority orElse mediumPriority orElse
+ _mediumPriority orElse lowPriority orElse _lowPriority
}
/**
@@ -1203,13 +1250,14 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
* rendering.
*/
protected implicit def nsToNsFuncToRenderOut(f: NodeSeq => NodeSeq) =
- new RenderOut((Box !! defaultHtml).map(f), internalFixedRender, if (autoIncludeJsonCode) Full(jsonToIncludeInCode & S.jsToAppend()) else {
+ new RenderOut((Box !! defaultHtml).map(f), internalFixedRender, if (autoIncludeJsonCode) Full(jsonToIncludeInCode & S.jsToAppend())
+ else {
S.jsToAppend match {
case Nil => Empty
case x :: Nil => Full(x)
case xs => Full(xs.reduceLeft(_ & _))
}
- }, Empty, false)
+ }, Empty, false)
/**
* Convert a Seq[Node] (the superclass of NodeSeq) to a RenderOut.
@@ -1218,17 +1266,21 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
* (in Java) will convert a NodeSeq to a RenderOut. This
* is helpful if you return a NodeSeq from your render method.
*/
- protected implicit def arrayToRenderOut(in: Seq[Node]): RenderOut = new RenderOut(Full(in: NodeSeq), internalFixedRender, if (autoIncludeJsonCode) Full(jsonToIncludeInCode & S.jsToAppend()) else {
- S.jsToAppend match {
- case Nil => Empty
- case x :: Nil => Full(x)
- case xs => Full(xs.reduceLeft(_ & _))
- }
- }, Empty, false)
+ protected implicit def arrayToRenderOut(in: Seq[Node]): RenderOut = new RenderOut(Full(in: NodeSeq), internalFixedRender, if (autoIncludeJsonCode) Full(jsonToIncludeInCode & S.jsToAppend())
+ else {
+ S.jsToAppend match {
+ case Nil => Empty
+ case x :: Nil => Full(x)
+ case xs => Full(xs.reduceLeft(_ & _))
+ }
+ }, Empty, false)
protected implicit def jsToXmlOrJsCmd(in: JsCmd): RenderOut = new RenderOut(Empty, internalFixedRender, if (autoIncludeJsonCode) Full(in & jsonToIncludeInCode & S.jsToAppend()) else Full(in & S.jsToAppend()), Empty, false)
- implicit def pairToPair(in: (String, Any)): (String, NodeSeq) = (in._1, Text(in._2 match {case null => "null" case s => s.toString}))
+ implicit def pairToPair(in: (String, Any)): (String, NodeSeq) = (in._1, Text(in._2 match {
+ case null => "null"
+ case s => s.toString
+ }))
implicit def nodeSeqToFull(in: NodeSeq): Box[NodeSeq] = Full(in)
@@ -1237,64 +1289,90 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
/**
* Similar with S.error
*/
- def error(n: String) {error(Text(n))}
+ def error(n: String) {
+ error(Text(n))
+ }
/**
* Similar with S.error
*/
- def error(n: NodeSeq) {notices += ((NoticeType.Error, n, Empty))}
+ def error(n: NodeSeq) {
+ notices += ((NoticeType.Error, n, Empty))
+ }
/**
* Similar with S.error
*/
- def error(id: String, n: NodeSeq) {notices += ((NoticeType.Error, n, Full(id)))}
+ def error(id: String, n: NodeSeq) {
+ notices += ((NoticeType.Error, n, Full(id)))
+ }
/**
* Similar with S.error
*/
- def error(id: String, n: String) {error(id, Text(n))}
+ def error(id: String, n: String) {
+ error(id, Text(n))
+ }
/**
* Similar with S.notice
*/
- def notice(n: String) {notice(Text(n))}
+ def notice(n: String) {
+ notice(Text(n))
+ }
/**
* Similar with S.notice
*/
- def notice(n: NodeSeq) {notices += ((NoticeType.Notice, n, Empty))}
+ def notice(n: NodeSeq) {
+ notices += ((NoticeType.Notice, n, Empty))
+ }
/**
* Similar with S.notice
*/
- def notice(id: String, n: NodeSeq) {notices += ((NoticeType.Notice, n, Full(id)))}
+ def notice(id: String, n: NodeSeq) {
+ notices += ((NoticeType.Notice, n, Full(id)))
+ }
/**
* Similar with S.notice
*/
- def notice(id: String, n: String) {notice(id, Text(n))}
+ def notice(id: String, n: String) {
+ notice(id, Text(n))
+ }
/**
* Similar with S.warning
*/
- def warning(n: String) {warning(Text(n))}
+ def warning(n: String) {
+ warning(Text(n))
+ }
/**
* Similar with S.warning
*/
- def warning(n: NodeSeq) {notices += ((NoticeType.Warning, n, Empty))}
+ def warning(n: NodeSeq) {
+ notices += ((NoticeType.Warning, n, Empty))
+ }
/**
* Similar with S.warning
*/
- def warning(id: String, n: NodeSeq) {notices += ((NoticeType.Warning, n, Full(id)))}
+ def warning(id: String, n: NodeSeq) {
+ notices += ((NoticeType.Warning, n, Full(id)))
+ }
/**
* Similar with S.warning
*/
- def warning(id: String, n: String) {warning(id, Text(n))}
+ def warning(id: String, n: String) {
+ warning(id, Text(n))
+ }
- private def clearNotices {notices clear}
+ private def clearNotices {
+ notices clear
+ }
}
@@ -1330,16 +1408,16 @@ private[http] class XmlOrJsCmd(val id: String,
*/
def toJavaScript(session: LiftSession, displayAll: Boolean): JsCmd = {
var ret: JsCmd = JsCmds.JsTry(JsCmds.Run("destroy_" + id + "();"), false) &
- ((if (ignoreHtmlOnJs) Empty else xml, javaScript, displayAll) match {
- case (Full(xml), Full(js), false) => LiftRules.jsArtifacts.setHtml(id, Helpers.stripHead(xml)) & JsCmds.JsTry(js, false)
- case (Full(xml), _, false) => LiftRules.jsArtifacts.setHtml(id, Helpers.stripHead(xml))
- case (Full(xml), Full(js), true) => LiftRules.jsArtifacts.setHtml(id + "_outer", (
- spanFunc(0, Helpers.stripHead(xml)) ++ fixedXhtml.openOr(Text("")))) & JsCmds.JsTry(js, false)
- case (Full(xml), _, true) => LiftRules.jsArtifacts.setHtml(id + "_outer", (
- spanFunc(0, Helpers.stripHead(xml)) ++ fixedXhtml.openOr(Text(""))))
- case (_, Full(js), _) => js
- case _ => JsCmds.Noop
- }) & JsCmds.JsTry(JsCmds.Run("destroy_" + id + " = function() {" + (destroy.openOr(JsCmds.Noop).toJsCmd) + "};"), false)
+ ((if (ignoreHtmlOnJs) Empty else xml, javaScript, displayAll) match {
+ case (Full(xml), Full(js), false) => LiftRules.jsArtifacts.setHtml(id, Helpers.stripHead(xml)) & JsCmds.JsTry(js, false)
+ case (Full(xml), _, false) => LiftRules.jsArtifacts.setHtml(id, Helpers.stripHead(xml))
+ case (Full(xml), Full(js), true) => LiftRules.jsArtifacts.setHtml(id + "_outer", (
+ spanFunc(0, Helpers.stripHead(xml)) ++ fixedXhtml.openOr(Text("")))) & JsCmds.JsTry(js, false)
+ case (Full(xml), _, true) => LiftRules.jsArtifacts.setHtml(id + "_outer", (
+ spanFunc(0, Helpers.stripHead(xml)) ++ fixedXhtml.openOr(Text(""))))
+ case (_, Full(js), _) => js
+ case _ => JsCmds.Noop
+ }) & JsCmds.JsTry(JsCmds.Run("destroy_" + id + " = function() {" + (destroy.openOr(JsCmds.Noop).toJsCmd) + "};"), false)
S.appendNotices(notices)
ret = S.noticesToJsCmd & ret
@@ -1349,7 +1427,7 @@ private[http] class XmlOrJsCmd(val id: String,
def inSpan: NodeSeq = xml.openOr(Text("")) ++ javaScript.map(s => Script(s)).openOr(Text(""))
def outSpan: NodeSeq = Script(Run("var destroy_" + id + " = function() {" + (destroy.openOr(JsCmds.Noop).toJsCmd) + "}")) ++
- fixedXhtml.openOr(Text(""))
+ fixedXhtml.openOr(Text(""))
}
/**
@@ -1358,20 +1436,35 @@ private[http] class XmlOrJsCmd(val id: String,
case class UpdateDefaultXml(xml: NodeSeq) extends CometMessage
case class PartialUpdateMsg(cmd: () => JsCmd) extends CometMessage
+
case object AskRender extends CometMessage
+
case class AnswerRender(response: XmlOrJsCmd, who: LiftCometActor, when: Long, displayAll: Boolean) extends CometMessage
+
case class PerformSetupComet2(initialReq: Box[Req]) extends CometMessage
+
case object ShutdownIfPastLifespan extends CometMessage
+
case class AskQuestion(what: Any, who: LiftCometActor, listeners: List[(ListenerId, AnswerRender => Unit)]) extends CometMessage
+
case class AnswerQuestion(what: Any, listeners: List[(ListenerId, AnswerRender => Unit)]) extends CometMessage
+
case class Listen(when: Long, uniqueId: ListenerId, action: AnswerRender => Unit) extends CometMessage
+
case class Unlisten(uniqueId: ListenerId) extends CometMessage
+
case class ActionMessageSet(msg: List[() => Any], req: Req) extends CometMessage
+
case class ReRender(doAll: Boolean) extends CometMessage
+
case class ListenerId(id: Long)
+
case class Error(id: Box[String], msg: NodeSeq) extends CometMessage
+
case class Warning(id: Box[String], msg: NodeSeq) extends CometMessage
+
case class Notice(id: Box[String], msg: NodeSeq) extends CometMessage
+
case object ClearNotices extends CometMessage
object Error {
@@ -1383,6 +1476,7 @@ object Error {
def apply(id: String, node: NodeSeq): Error = Error(Full(id), node)
}
+
object Warning {
def apply(node: NodeSeq): Warning = Warning(Empty, node)
@@ -1392,6 +1486,7 @@ object Warning {
def apply(id: String, node: NodeSeq): Warning = Warning(Full(id), node)
}
+
object Notice {
def apply(node: NodeSeq): Notice = Notice(Empty, node)
View
12 web/webkit/src/main/scala/net/liftweb/http/LiftServlet.scala
@@ -26,6 +26,7 @@ import util.Helpers._
import js._
import auth._
import provider._
+import json.JsonAST.JValue
class LiftServlet extends Loggable {
@@ -417,16 +418,16 @@ class LiftServlet extends Loggable {
toReturn
}
- private def extractVersion(path: List[String]) {
+ private def extractVersion[T](path: List[String])(f: => T): T = {
path match {
- case first :: second :: _ => RenderVersion.set(second)
- case _ =>
+ case first :: second :: _ => RenderVersion.doWith(second)(f)
+ case _ => f
}
}
private def handleAjax(liftSession: LiftSession,
requestState: Req): Box[LiftResponse] = {
- extractVersion(requestState.path.partPath)
+ extractVersion(requestState.path.partPath) {
LiftRules.cometLogger.debug("AJAX Request: " + liftSession.uniqueId + " " + requestState.params)
tryo {
@@ -451,6 +452,7 @@ class LiftServlet extends Loggable {
val what2 = what.flatMap {
case js: JsCmd => List(js)
+ case jv: JValue => List(jv)
case n: NodeSeq => List(n)
case js: JsCommands => List(js)
case r: LiftResponse => List(r)
@@ -459,6 +461,7 @@ class LiftServlet extends Loggable {
val ret: LiftResponse = what2 match {
case (json: JsObj) :: Nil => JsonResponse(json)
+ case (jv: JValue) :: Nil => JsonResponse(jv)
case (js: JsCmd) :: xs => {
(JsCommands(S.noticesToJsCmd :: Nil) &
((js :: xs).flatMap {
@@ -489,6 +492,7 @@ class LiftServlet extends Loggable {
LiftSession.onEndServicing.foreach(_(liftSession, requestState, ret))
}
ret
+ }
}
/**
View
50 web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala
@@ -1,5 +1,5 @@
/*
- * Copyright 2007-2011 WorldWide Conferencing, LLC
+ * Copyright 2007-2012 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.
@@ -17,13 +17,9 @@
package net.liftweb
package http
-import java.io.InputStream
-import java.lang.reflect.{Method, Modifier, InvocationTargetException}
-import java.util.concurrent.TimeUnit
-import java.util.Locale
+import java.lang.reflect.{Method}
-import collection.mutable.{HashMap, ArrayBuffer, ListBuffer}
-import reflect.Manifest
+import collection.mutable.{HashMap, ListBuffer}
import xml._
import common._
@@ -397,10 +393,24 @@ private[http] object RenderVersion {
def get: String = ver.is
- def doWith[T](v: String)(f: => T): T = ver.doWith(v)(f)
+ def doWith[T](v: String)(f: => T): T = {
+ val ret: Box[T] =
+ for {
+ sess <- S.session
+ func <- sess.findFunc(v).collect {
+ case f: S.PageStateHolder => f
+ }
+ } yield {
+ val tret = ver.doWith(v)(func.runInContext(f))
+
+ if (S.functionMap.size > 0) {
+ sess.updateFunctionMap(S.functionMap, this.get, millis)
+ S.clearFunctionMap
+ }
+ tret
+ }
- def set(value: String) {
- ver(value)
+ ret openOr ver.doWith(v)(f)
}
}
@@ -620,6 +630,16 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
}
}
+
+ /**
+ * Find a function in the function lookup table. You probably never need to do this, but
+ * well, you can look them up.
+ */
+ def findFunc(funcName: String): Option[S.AFuncHolder] =
+ synchronized {
+ messageCallback.get(funcName)
+ }
+
/**
* Executes the user's functions based on the query parameters
*/
@@ -997,6 +1017,9 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
// Phase 2: Head & Tail merge, add additional elements to body & head
val xml = merge(rawXml, request)
+ // snapshot for ajax calls
+ messageCallback(S.renderVersion) = S.PageStateHolder(Full(S.renderVersion), this)
+
// But we need to update the function map because there
// may be addition functions created during the JsToAppend processing
// See issue #983
@@ -1499,7 +1522,7 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
def executeInScope[T](req: Box[Req], renderVersion: String)(f: => T): T = {
def doExec(): T = {
- RenderVersion.set(renderVersion)
+ RenderVersion.doWith(renderVersion) {
try {
f
} finally {
@@ -1509,6 +1532,7 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
S.clearFunctionMap
}
}
+ }
}
req match {
@@ -2051,7 +2075,7 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
}
val id = Full(act.uniqueId)
- messageCallback.keys.toList.foreach {
+ messageCallback.keysIterator.foreach {
k =>
val f = messageCallback(k)
if (f.owner == id) {
@@ -2149,7 +2173,7 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
case (id, replacement) => (("#" + id) #> replacement)
}.reduceLeft(_ & _)(s)
}
- case _ => atWhat.values.flatMap(_.toSeq).toList
+ case _ => atWhat.valuesIterator.toSeq.flatMap(_.toSeq).toList
}
}
View
23 web/webkit/src/main/scala/net/liftweb/http/S.scala
@@ -27,11 +27,10 @@ import actor.LAFuture
import util._
import Helpers._
import js._
-
-import builtin.snippet._
import provider._
import http.rest.RestContinuation
+
class SJBridge {
def s = S
}
@@ -219,6 +218,24 @@ object S extends S {
}
/**
+ * We create one of these dudes and put it
+ */
+ private[http] final case class PageStateHolder(owner: Box[String], session: LiftSession) extends AFuncHolder {
+ private val loc = S.location
+ private val snapshot: Function1[Function0[Any], Any] = RequestVarHandler.generateSnapshotRestorer()
+ override def sessionLife: Boolean = false
+
+ def apply(in: List[String]): Any = {
+ error("You shouldn't really be calling apply on this dude...")
+ }
+
+ def runInContext[T](f: => T): T = {
+ val ret = snapshot(() => f).asInstanceOf[T]
+ ret
+ }
+ }
+
+ /**
* The companion object that generates AFuncHolders from other functions
*/
object AFuncHolder {
@@ -998,7 +1015,7 @@ trait S extends HasParams with Loggable {
/**
* Returns the logical page_id of the current request. All RequestVars for a current page share this id.
*/
- def renderVersion = RenderVersion.get
+ def renderVersion: String = RenderVersion.get
/**
* The URI of the current request (not re-written). The URI is the portion of the request
View
42 web/webkit/src/main/scala/net/liftweb/http/SHtml.scala
@@ -201,7 +201,7 @@ trait SHtml {
* @return the function ID and JavaScript that makes the call
*/
private def jsonCall_*(jsCalcValue: JsExp, func: AFuncHolder): (String, JsExp) =
- fmapFunc(contextFuncBuilder(func))(name =>
+ fmapFunc((func))(name =>
(name, makeAjaxCall(JsRaw("'" + name + "=' + encodeURIComponent(JSON.stringify(" + jsCalcValue.toJsCmd + "))"))))
/**
@@ -215,7 +215,7 @@ trait SHtml {
private def jsonCall_*(jsCalcValue: JsExp,
ajaxContext: AjaxContext,
func: AFuncHolder): (String, JsExp) =
- fmapFunc(contextFuncBuilder(func))(name =>
+ fmapFunc((func))(name =>
(name, makeAjaxCall(JsRaw("'" + name + "=' + encodeURIComponent(JSON.stringify(" + jsCalcValue.toJsCmd + "))"), ajaxContext)))
def fajaxCall[T](jsCalcValue: JsExp, func: String => JsCmd)(f: (String, JsExp) => T): T = {
@@ -240,7 +240,7 @@ trait SHtml {
* @return the JavaScript that makes the call
*/
private def ajaxCall_*(jsCalcValue: JsExp, func: AFuncHolder): (String, JsExp) =
- fmapFunc(contextFuncBuilder(func))(name =>
+ fmapFunc((func))(name =>
(name, makeAjaxCall(JsRaw("'" + name + "=' + encodeURIComponent(" + jsCalcValue.toJsCmd + ")"))))
/**
@@ -254,7 +254,7 @@ trait SHtml {
private def ajaxCall_*(jsCalcValue: JsExp,
ajaxContext: AjaxContext,
func: AFuncHolder): (String, JsExp) =
- fmapFunc(contextFuncBuilder(func))(name =>
+ fmapFunc((func))(name =>
(name, makeAjaxCall(JsRaw("'" + name + "=' + encodeURIComponent(" + jsCalcValue.toJsCmd + ")"), ajaxContext)))
@@ -271,7 +271,7 @@ trait SHtml {
* @return a button to put on your page
*/
def ajaxButton(text: NodeSeq, func: () => JsCmd, attrs: ElemAttr*): Elem = {
- attrs.foldLeft(fmapFunc(contextFuncBuilder(func))(name =>
+ attrs.foldLeft(fmapFunc((func))(name =>
<button onclick={makeAjaxCall(Str(name + "=true")).toJsCmd +
"; return false;"}>{text}</button>))((e, f) => f(e))
}
@@ -343,7 +343,7 @@ trait SHtml {
*
*/
def jsonButton(text: NodeSeq, func: () => JsObj, ajaxContext: JsonContext, attrs: ElemAttr*): Elem = {
- attrs.foldLeft(fmapFunc(contextFuncBuilder(func))(name =>
+ attrs.foldLeft(fmapFunc((func))(name =>
<button onclick={makeAjaxCall(Str(name + "=true"), ajaxContext).toJsCmd +
"; return false;"}>{text}</button>))((e, f) => f(e))
}
@@ -358,7 +358,7 @@ trait SHtml {
* @return a button to put on your page
*/
def ajaxButton(text: NodeSeq, jsExp: JsExp, func: String => JsCmd, attrs: ElemAttr*): Elem = {
- attrs.foldLeft(fmapFunc(contextFuncBuilder(SFuncHolder(func)))(name =>
+ attrs.foldLeft(fmapFunc((SFuncHolder(func)))(name =>
<button onclick={makeAjaxCall(JsRaw(name.encJs + "+'='+encodeURIComponent(" + jsExp.toJsCmd + ")")).toJsCmd +
"; return false;"}>{text}</button>))((e, f) => f(e))
}
@@ -393,7 +393,7 @@ trait SHtml {
* @return a button to put on your pagejsFunc.params ++ List(AnonFunc(makeAjaxCall(Str(name+"=true"))))
*/
def ajaxButton(text: NodeSeq, jsFunc: Call, func: () => JsCmd, attrs: ElemAttr*): Elem = {
- attrs.foldLeft(fmapFunc(contextFuncBuilder(func))(name =>
+ attrs.foldLeft(fmapFunc((func))(name =>
<button onclick={deferCall(Str(name + "=true"), jsFunc).toJsCmd + "; return false;"}>{text}</button>))(_ % _)
}
@@ -493,7 +493,7 @@ trait SHtml {
*/
def a(func: () => JsCmd, body: NodeSeq, attrs: ElemAttr*): Elem = {
val key = formFuncName
- addFunctionMap(key, contextFuncBuilder((a: List[String]) => func()))
+ addFunctionMap(key, ((a: List[String]) => func()))
attrs.foldLeft(<lift:a key={key}>{body}</lift:a>)(_ % _)
}
@@ -508,7 +508,7 @@ trait SHtml {
* @param attrs - the anchor node attributes
*/
def a(jsFunc: Call, func: () => JsCmd, body: NodeSeq, attrs: ElemAttr*): Elem = {
- attrs.foldLeft(fmapFunc(contextFuncBuilder(func))(name =>
+ attrs.foldLeft(fmapFunc((func))(name =>
<a href="javascript://" onclick={deferCall(Str(name + "=true"), jsFunc).toJsCmd + "; return false;"}>{body}</a>))(_ % _)
}
@@ -517,7 +517,7 @@ trait SHtml {
body: NodeSeq,
attrs: ElemAttr*): Elem = {
- attrs.foldLeft(fmapFunc(contextFuncBuilder(func))(name =>
+ attrs.foldLeft(fmapFunc((func))(name =>
<a href="javascript://" onclick={makeAjaxCall(Str(name + "=true"), jsonContext).toJsCmd + "; return false;"}>{body}</a>))(_ % _)
}
@@ -553,7 +553,7 @@ trait SHtml {
def toggleKids(head: Elem, visible: Boolean, func: () => JsCmd, kids: Elem): NodeSeq = {
- fmapFunc(contextFuncBuilder(func)) {
+ fmapFunc((func)) {
funcName =>
val (nk, id) = findOrAddId(kids)
@@ -631,7 +631,7 @@ trait SHtml {
val raw = (funcName: String, value: String) => JsRaw("'" + funcName + "=' + encodeURIComponent(" + value + ".value)")
val key = formFuncName
- fmapFunc(contextFuncBuilder(func)) {
+ fmapFunc((func)) {
funcName =>
(attrs.foldLeft(<input type="text" value={value}/>)(_ % _)) %
("onkeypress" -> """liftUtils.lift_blurIfReturn(event)""") %
@@ -683,7 +683,7 @@ trait SHtml {
val raw = (funcName: String, value: String) => JsRaw("'" + funcName + "=' + encodeURIComponent(" + value + ".value)")
val key = formFuncName
- fmapFunc(contextFuncBuilder(func)) {
+ fmapFunc((func)) {
funcName =>
(attrs.foldLeft(<textarea>{value}</textarea>)(_ % _)) %
("onblur" -> (jsFunc match {
@@ -746,7 +746,7 @@ trait SHtml {
* @param attrs - the balance of the attributes for the tag
*/
def area(shape: AreaShape, func: () => JsCmd, alt: String, attrs: ElemAttr*): Elem = {
- fmapFunc(contextFuncBuilder(func)) {
+ fmapFunc((func)) {
funcName =>
area(shape, alt, (("onclick" -> (makeAjaxCall(Str(funcName + "=true")).toJsCmd +
"; return false;")): ElemAttr) :: attrs.toList :_*)
@@ -771,7 +771,7 @@ trait SHtml {
val raw = (funcName: String, value: String) => JsRaw("'" + funcName + "=' + " + value + ".checked")
val key = formFuncName
- fmapFunc(contextFuncBuilder(func)) {
+ fmapFunc((func)) {
funcName =>
(attrs.foldLeft(<input type="checkbox"/>)(_ % _)) %
checked(value) %
@@ -905,7 +905,7 @@ trait SHtml {
val vals = opts.map(_._1)
val testFunc = LFuncHolder(in => in.filter(v => vals.contains(v)) match {case Nil => false case xs => func(xs)}, func.owner)
- fmapFunc(contextFuncBuilder(testFunc)) {
+ fmapFunc((testFunc)) {
funcName =>
(attrs.foldLeft(<select>{opts.flatMap {case (value, text) => (<option value={value}>{text}</option>) % selected(deflt.exists(_ == value))}}</select>)(_ % _)) %
("onchange" -> (jsFunc match {
@@ -916,7 +916,7 @@ trait SHtml {
}
def ajaxInvoke(func: () => JsCmd): (String, JsExp) =
- fmapFunc(contextFuncBuilder(NFuncHolder(func)))(name => (name, makeAjaxCall(name + "=true")))
+ fmapFunc((NFuncHolder(func)))(name => (name, makeAjaxCall(name + "=true")))
/**
* Build a swappable visual element. If the shown element is clicked on, it turns into the hidden element and when
@@ -1412,7 +1412,7 @@ trait SHtml {
*/
def button(strOrNodeSeq: StringOrNodeSeq, func: () => Any, attrs: ElemAttr*): Elem = {
def doit: Elem = {
- attrs.foldLeft(fmapFunc(contextFuncBuilder(func))(name =>
+ attrs.foldLeft(fmapFunc((func))(name =>
<button type="submit" name={name} value="_">{
strOrNodeSeq.nodeSeq}</button>))(_ % _)
}
@@ -1454,7 +1454,7 @@ trait SHtml {
*/
def ajaxSubmit(value: String, func: () => JsCmd, attrs: ElemAttr*): Elem = {
val funcName = "z" + Helpers.nextFuncName
- addFunctionMap(funcName, contextFuncBuilder(func))
+ addFunctionMap(funcName, (func))
(attrs.foldLeft(<input type="submit" name={funcName}/>)(_ % _)) %
new UnprefixedAttribute("value", Text(value), Null) %
@@ -1583,7 +1583,7 @@ trait SHtml {
*/
def submitAjaxForm(formId: String, func: () => JsCmd): JsCmd = {
val funcName = "Z" + Helpers.nextFuncName
- addFunctionMap(funcName, contextFuncBuilder(func))
+ addFunctionMap(funcName, (func))
makeAjaxCall(JsRaw(
LiftRules.jsArtifacts.serialize(formId).toJsCmd + " + " +
Please sign in to comment.
Something went wrong with that request. Please try again.