
net.liftweb.builtin.snippet.LazyLoad.scala Maven / Gradle / Ivy
The newest version!
/*
* 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.
* 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 builtin
package snippet
import xml._
import http._
import common._
import actor._
import util._
import http.js._
import JsCmds._
import JE._
import S._
import Helpers._
/**
* Enclose your snippet tags on your template with LazyLoad and the snippet will execute
* on a different thread, which avoids blocking the page render.
*/
object LazyLoad extends DispatchSnippet {
private object myFuncName extends TransientRequestVar(Helpers.nextFuncName)
private object myActor extends TransientRequestVar[Box[CometActor]](Empty)
def dispatch: DispatchIt = {
case _ => render _
}
/**
* Enclose your snippet like this:
*
*
* <div class="lift:LazyLoad">
* <div class="lift:MyLongRunningSnippet"></div>
* </div>
*
*
* You can add the template attribute to the LazyLoad tag and instead of
* showing the spinning circle, it will render your template.
*
*
*
* <div class="lift:LazyLoad?template='my-nice-wait-message-template'">
* <div class="lift:MyLongRunningSnippet"></div>
* </div>
*
*
*
*/
def render(xhtml: NodeSeq): NodeSeq = {
(for {
session <- S.session ?~ ("FIXME: Invalid session")
} yield {
// if we haven't created the actor yet, register on this
// thread to create the AsyncRenderComet actor
if (myActor.isEmpty) {
LiftRules.cometCreationFactory.request.set(
(ccinfo: CometCreationInfo) =>
ccinfo match {
case CometCreationInfo(theType @ "AsyncRenderComet",
name,
defaultXml,
attributes,
session) => {
val ret = new AsyncRenderComet()
ret.initCometActor(session,
Full(theType),
name, defaultXml, attributes)
ret ! PerformSetupComet2(if (ret.sendInitialReq_?)
S.request.map(_.snapshot) else Empty)
// and save it in the request var
myActor.set(Full(ret))
Full(ret)
}
case _ => Empty
})
}
val id = Helpers.nextFuncName
val func: () => JsCmd =
session.buildDeferredFunction(() => Replace(id, xhtml))
{
S.attr("template") match {
case Full(template) =>
case _ =>
}
}
++ (myActor.is match {
case Full(actor) => actor ! Ready(func); NodeSeq.Empty
case _ => session.setupComet("AsyncRenderComet", Full(myFuncName.is), Ready(func))
})
}) match {
case Full(x) => x
case Empty => Comment("FIX"+ "ME: session or request are invalid")
case Failure(msg, _, _) => Comment(msg)
}
}
}
private case class Ready(js: () => JsCmd)
private case class Render(js: JsCmd)
/**
* The Comet Actor for sending down the computed page fragments
*
*/
class AsyncRenderComet extends CometActor {
override def lifespan: Box[TimeSpan] = Full(90 seconds)
def render = NodeSeq.Empty
// make this method visible so that we can initialize the actor
override def initCometActor(theSession: LiftSession,
theType: Box[String],
name: Box[String],
defaultXml: NodeSeq,
attributes: Map[String, String]) {
super.initCometActor(theSession, theType, name, defaultXml,
attributes)
}
override def lowPriority : PartialFunction[Any, Unit] = {
// farm the request off to another thread
case Ready(js) =>
Schedule.schedule(() => this ! Render(js()), 0 seconds)
// render it
case Render(js) =>
partialUpdate(js)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy