Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

High Wire: Fix appendJs when invoked from inside a toJsCmd def #1711

Merged
merged 3 commits into from Aug 10, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -719,7 +719,7 @@ trait BaseCometActor extends LiftActor with LiftCometActor with CssBindImplicits
case e: Exception => reportError("Message dispatch for " + in, e)
}

val updatedJs = S.jsToAppend
val updatedJs = S.jsToAppend(clearAfterReading = true)
if (updatedJs.nonEmpty) {
partialUpdate(updatedJs)
}
Expand Down
2 changes: 1 addition & 1 deletion web/webkit/src/main/scala/net/liftweb/http/LiftMerge.scala
Expand Up @@ -74,7 +74,7 @@ private[http] trait LiftMerge {
LiftRules.javaScriptSettings.vend().map { settingsFn =>
LiftJavaScript.initCmd(settingsFn(this))
}.toList ++
S.jsToAppend ++
S.jsToAppend() ++
eventJs

allJs.foldLeft(js.JsCmds.Noop)(_ & _)
Expand Down
25 changes: 13 additions & 12 deletions web/webkit/src/main/scala/net/liftweb/http/LiftServlet.scala
Expand Up @@ -632,15 +632,14 @@ class LiftServlet extends Loggable {
(JsCommands(S.noticesToJsCmd :: Nil) &
(js :: (xs.collect {
case js: JsCmd => js
}).reverse) &
S.jsToAppend
}).reverse)
).toResponse
}

case (n: Node) :: _ => XmlResponse(n)
case (ns: NodeSeq) :: _ => XmlResponse(Group(ns))
case (r: LiftResponse) :: _ => r
case _ => JsCommands(S.noticesToJsCmd :: JsCmds.Noop :: S.jsToAppend).toResponse
case _ => JsCommands(S.noticesToJsCmd :: JsCmds.Noop :: Nil).toResponse
}

LiftRules.cometLogger.debug("AJAX Response: " + liftSession.underlyingId + " " + ret)
Expand Down Expand Up @@ -879,15 +878,17 @@ class LiftServlet extends Loggable {

actors foreach (_._1 ! ClearNotices)

val addl: List[JsCmd] =
(for {
req <- S.request
rendVer <- extractRenderVersion(req.path.partPath)
} yield RenderVersion.doWith(rendVer) {
S.jsToAppend
}) openOr Nil

(new JsCommands(JsCmds.Run(jsUpdateTime) :: jsUpdateStuff ::: addl)).toResponse
val jsCommands =
new JsCommands(JsCmds.Run(jsUpdateTime) :: jsUpdateStuff)

// If we need to, ensure we capture JS from this request's render version.
// The comet actor will already have handled the comet's version.
S.request.flatMap(req => extractRenderVersion(req.path.partPath)) match {
case Full(additionalVersion) =>
RenderVersion.doWith(additionalVersion) { jsCommands.toResponse }
case _ =>
jsCommands.toResponse
}
}

private def extractRenderVersion(in: List[String]): Box[String] = in match {
Expand Down
22 changes: 15 additions & 7 deletions web/webkit/src/main/scala/net/liftweb/http/S.scala
Expand Up @@ -937,7 +937,7 @@ trait S extends HasParams with Loggable with UserAgentCalculator {
*
* @see appendJs
*/
def jsToAppend(): List[JsCmd] = {
def jsToAppend(clearAfterReading: Boolean = false): List[JsCmd] = {
import js.JsCmds._

val globalJs = _globalJsToAppend.is.toList
Expand All @@ -948,14 +948,22 @@ trait S extends HasParams with Loggable with UserAgentCalculator {
}
val cometJs = commandsForComets

globalJs ::: {
postPageJs ::: cometJs ::: _jsToAppend.is.toList match {
case Nil =>
Nil
case loadJs =>
List(OnLoad(loadJs))
val allJs =
globalJs ::: {
postPageJs ::: cometJs ::: _jsToAppend.is.toList match {
case Nil =>
Nil
case loadJs =>
List(OnLoad(loadJs))
}
}

if (clearAfterReading) {
_globalJsToAppend(ListBuffer())
_jsToAppend(ListBuffer())
}

allJs
}

/**
Expand Down
18 changes: 17 additions & 1 deletion web/webkit/src/main/scala/net/liftweb/http/js/JsCommands.scala
Expand Up @@ -31,13 +31,29 @@ object JsCommands {
def apply(in: JsExp) = new JsCommands(List(in.cmd))
}

/**
* A container for accumulating `[[JsCmd]]`s that need to be sent to the client.
* When `[[toResponse]]` is called to finalize the response, in addition to the
* JS passed directly to this instance, the commands in `[[S.jsToAppend]]` are
* also read and included in the response. Also in this process, all of the
* `JsCmd` instances have their `toJsCmd` methods called to convert them to a
* string.
*
* @note The contents of `jsToAppend` are cleared in this process!
*/
class JsCommands(val reverseList: List[JsCmd]) {
def &(in: JsCmd) = new JsCommands(in :: reverseList)

def &(in: List[JsCmd]) = new JsCommands(in.reverse ::: reverseList)

def toResponse = {
val data = reverseList.reverse.map(_.toJsCmd).mkString("\n").getBytes("UTF-8")
// Evaluate all toJsCmds, which may in turn call S.append[Global]Js.
val containedJs = reverseList.reverse.map(_.toJsCmd)

val toAppend = S.jsToAppend(clearAfterReading = true).map(_.toJsCmd)

val data = (containedJs ++ toAppend).mkString("\n").getBytes("UTF-8")

InMemoryResponse(data, List("Content-Length" -> data.length.toString, "Content-Type" -> "text/javascript; charset=utf-8"), S.responseCookies, 200)
}
}
Expand Down