The total chat app, including the ask/answer component for soliciting a name comments, etc. is listed on this page. There is no special code to support AJAX/Comet (all the wrapping is done automatically by Lift).

When the Chat comet widget is added to the page, it needs to solict the user for a "chat name". It asks the "AskName" comet widget for the name. Until the AskName comet widget provides a name, all rendering messages are forwarded to AskName. Here's the code for the "AskName":

class AskName extends CometActor {
  def render = 
  ajaxForm(<div>What is your username?</div> ++
           text("",name => answer(name.trim)) ++
           <input type="submit" value="Enter"/>)
}

When the user submits the form, the question asked by the Chat comet widget is answered with the value the user submitted. This is similar to the ask/answer paradigm in Seaside, except that there's no need for continuations.

Now, onto the heart of the chat app:

class Chat extends CometActor with CometListener {
  private var userName = ""
  private var chats: List[ChatLine] = Nil
  private lazy val infoId = uniqueId + "_info"
  private lazy val infoIn = uniqueId + "_in"
  private lazy val inputArea = findKids(defaultXml, "chat", "input")
  private lazy val bodyArea = findKids(defaultXml, "chat", "body")
  private lazy val singleLine = deepFindKids(bodyArea, "chat", "list")

  // handle an update to the chat lists
  // by diffing the lists and then sending a partial update
  // to the browser
  override def lowPriority = {
    case ChatServerUpdate(value) =>
      val update = (value -- chats).reverse.map(b => AppendHtml(infoId, line(b)))
      partialUpdate(update)
      chats = value
  }

  // render the input area by binding the
  // appropriate dynamically generated code to the
  // view supplied by the template
  override lazy val fixedRender: Box[NodeSeq] = 
  ajaxForm(After(100, SetValueAndFocus(infoIn, "")),
           bind("chat", inputArea, 
                "input" -> text("", sendMessage _, "id" -> infoIn)))

  // send a message to the chat server
  private def sendMessage(msg: String) = ChatServer ! ChatServerMsg(userName, msg.trim)

  // display a line
  private def line(c: ChatLine) = bind("list", singleLine,
                                       "when" -> hourFormat(c.when),
                                       "who" -> c.user,
                                       "msg" -> c.msg)

  // display a list of chats
  private def displayList(in: NodeSeq): NodeSeq = chats.reverse.flatMap(line)

  // render the whole list of chats
  override def render = 
  bind("chat", bodyArea,
       "name" -> userName,
       AttrBindParam("id", Text(infoId), "id"),
       "list" -> displayList _)

  // setup the component
  override def localSetup {
    askForName
    super.localSetup
  }

  // register as a listener
  def registerWith = ChatServer

  // ask for the user's name
  private def askForName {
    if (userName.length == 0) {
      ask(new AskName, "what's your username") {
        case s: String if (s.trim.length > 2) =>
          userName = s.trim
          reRender(true)

        case _ =>
          askForName
          reRender(false)
      }
    }
  }

}

This example demonstrates the power of Scala's Actors and Lift. With very few lines of code, we've got a complete AJAX/Comet app that has Seaside style Ask/Answer for building modal dialogs.