Skip to content

Commit

Permalink
Got some listing stuff working
Browse files Browse the repository at this point in the history
  • Loading branch information
dpp committed Feb 15, 2011
1 parent 7229573 commit 3927fcc
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 33 deletions.
20 changes: 15 additions & 5 deletions core/util/src/main/scala/net/liftweb/util/ListHelpers.scala
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -52,15 +52,20 @@ trait ListHelpers {
@tailrec def loop(o: List[T], n: List[T]) { @tailrec def loop(o: List[T], n: List[T]) {
(o, n) match { (o, n) match {
case (o, Nil) => o.foreach(t => ret += f(RemoveDelta(t))) case (o, Nil) => o.foreach(t => ret += f(RemoveDelta(t)))
case (Nil, n) => n.foreach(t => ret += f(AppendDelta(t))) case (Nil, n) => {
n.foreach{
t => ret += f(insertAfter match {
case Full(x) => InsertAfterDelta(t, x)
case _ => AppendDelta(t)
})
insertAfter = Full(t)
}
}

case (o :: or, n :: nr) if o == n => { case (o :: or, n :: nr) if o == n => {
insertAfter = Full(n) insertAfter = Full(n)
loop(or, nr) loop(or, nr)
} }
case (o :: or, nr) if !nr.contains(o) => {
ret += f(RemoveDelta(o))
loop(or, nr)
}


case (or, n :: nr) if !or.contains(n) => { case (or, n :: nr) if !or.contains(n) => {
insertAfter match { insertAfter match {
Expand All @@ -70,6 +75,11 @@ trait ListHelpers {
insertAfter = Full(n) insertAfter = Full(n)
loop(or, nr) loop(or, nr)
} }

case (o :: or, nr) => {
ret += f(RemoveDelta(o))
loop(or, nr)
}
} }
} }


Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ trait StringHelpers {
what.charAt(pos) match { what.charAt(pos) match {
case c @ ('\\' | '\'') => sb.append(escChar(c)) case c @ ('\\' | '\'') => sb.append(escChar(c))
case '"' => sb.append("\\\"") case '"' => sb.append("\\\"")
case c if c < ' ' || c > '~' => sb.append(escChar(c)) case c if c < ' ' || c > '~' || c == ']' || c.toInt >= 127 => sb.append(escChar(c))
case c => sb.append(c) case c => sb.append(c)
} }
pos += 1 pos += 1
Expand Down
10 changes: 7 additions & 3 deletions core/util/src/test/scala/net/liftweb/util/ListHelpersSpec.scala
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -32,26 +32,30 @@ object ListHelpersSpec extends Specification with ListHelpers {
ret must_== List("ok") ret must_== List("ok")
} }


"prepend and append" in { "prepend and append 2,4, 99" in {
val ret = delta(List(2,4,99), List(1,2,3,4,5)) { val ret = delta(List(2,4,99), List(1,2,3,4,5)) {
case InsertAfterDelta(3, 2) => "ok" case InsertAfterDelta(3, 2) => "ok"
case AppendDelta(5) => "ok5" case AppendDelta(5) => "ok5"
case RemoveDelta(99) => "99" case RemoveDelta(99) => "99"
case InsertAtStartDelta(1) => "1" case InsertAtStartDelta(1) => "1"
case InsertAfterDelta(5, 4) => "ok5"
} }


ret must_== List("1", "ok", "99", "ok5") ret must_== List("1", "ok", "ok5", "99")
} }


"prepend and append" in { "prepend and append" in {
val ret = delta(List(4,2,99), List(1,2,3,4,5)) { val ret = delta(List(4,2,99), List(1,2,3,4,5)) {
case InsertAfterDelta(3, 2) => "ok" case InsertAfterDelta(3, 2) => "ok"
case InsertAfterDelta(4, 3) => "ok3"
case RemoveDelta(4) => "r4"
case AppendDelta(5) => "ok5" case AppendDelta(5) => "ok5"
case RemoveDelta(99) => "99" case RemoveDelta(99) => "99"
case InsertAtStartDelta(1) => "1" case InsertAtStartDelta(1) => "1"
case InsertAfterDelta(5, 4) => "ok5"
} }


ret must_== List("1", "ok", "99", "ok5") ret must_== List("1", "r4", "ok", "ok3", "ok5", "99")
} }


} }
Expand Down
34 changes: 17 additions & 17 deletions web/webkit/src/main/scala/net/liftweb/http/CometActor.scala
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -378,15 +378,15 @@ trait LiftCometActor extends TypedActor[Any, Any] with ForwardableActor[Any, Any
private[http] def callInitCometActor(theSession: LiftSession, private[http] def callInitCometActor(theSession: LiftSession,
theType: Box[String], theType: Box[String],
name: Box[String], name: Box[String],
defaultXml: NodeSeq, defaultHtml: NodeSeq,
attributes: Map[String, String]) { attributes: Map[String, String]) {
initCometActor(theSession, theType, name, defaultXml, attributes) initCometActor(theSession, theType, name, defaultHtml, attributes)
} }


protected def initCometActor(theSession: LiftSession, protected def initCometActor(theSession: LiftSession,
theType: Box[String], theType: Box[String],
name: Box[String], name: Box[String],
defaultXml: NodeSeq, defaultHtml: NodeSeq,
attributes: Map[String, String]): Unit attributes: Map[String, String]): Unit


def jsonCall: JsonCall def jsonCall: JsonCall
Expand Down Expand Up @@ -547,16 +547,16 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
protected def initCometActor(theSession: LiftSession, protected def initCometActor(theSession: LiftSession,
theType: Box[String], theType: Box[String],
name: Box[String], name: Box[String],
defaultXml: NodeSeq, defaultHtml: NodeSeq,
attributes: Map[String, String]) { attributes: Map[String, String]) {
if (!dontCacheRendering) { if (!dontCacheRendering) {
lastRendering = RenderOut(Full(defaultXml), lastRendering = RenderOut(Full(defaultHtml),
Empty, Empty, Empty, false) Empty, Empty, Empty, false)
} }


this._theType = theType this._theType = theType
this._theSession = theSession this._theSession = theSession
this._defaultXml = defaultXml this._defaultHtml = defaultHtml
this._name = name this._name = name
this._attributes = attributes this._attributes = attributes
} }
Expand Down Expand Up @@ -688,10 +688,10 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
/** /**
* A helpful implicit conversion that takes a NodeSeq => NodeSeq * A helpful implicit conversion that takes a NodeSeq => NodeSeq
* (for example a CssSel) and converts it to a Box[NodeSeq] by * (for example a CssSel) and converts it to a Box[NodeSeq] by
* applying the function to defaultXml * applying the function to defaultHtml
*/ */
protected implicit def nodeSeqFuncToBoxNodeSeq(f: NodeSeq => NodeSeq): protected implicit def nodeSeqFuncToBoxNodeSeq(f: NodeSeq => NodeSeq):
Box[NodeSeq] = Full(f(defaultXml)) Box[NodeSeq] = Full(f(defaultHtml))


/** /**
* Handle messages sent to this Actor before the * Handle messages sent to this Actor before the
Expand Down Expand Up @@ -743,12 +743,12 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
performReRender(true) performReRender(true)


/** /**
* Update the defaultXml... sent in dev mode * Update the defaultHtml... sent in dev mode
*/ */
case UpdateDefaultXml(xml) => { case UpdateDefaultXml(xml) => {
val redo = xml != _defaultXml val redo = xml != _defaultHtml


_defaultXml = xml _defaultHtml = xml


if (redo) performReRender(false) if (redo) performReRender(false)
} }
Expand Down Expand Up @@ -853,7 +853,7 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
* There are implicit conversions for NodeSeq, so you can return a pile of * There are implicit conversions for NodeSeq, so you can return a pile of
* XML right here. There's an implicit conversion for NodeSeq => NodeSeq, * XML right here. There's an implicit conversion for NodeSeq => NodeSeq,
* so you can return a function (e.g., a CssBindFunc) that will convert * so you can return a function (e.g., a CssBindFunc) that will convert
* the defaultXml to the correct output. There's an implicit conversion * the defaultHtml to the correct output. There's an implicit conversion
* from JsCmd, so you can return a pile of JavaScript that'll be shipped * from JsCmd, so you can return a pile of JavaScript that'll be shipped
* to the browser. * to the browser.
*/ */
Expand Down Expand Up @@ -980,12 +980,12 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
} }


/** /**
* A helper for binding which uses the defaultXml property. * A helper for binding which uses the defaultHtml property.
*/ */
def bind(prefix: String, vals: BindParam*): NodeSeq = bind(prefix, _defaultXml, vals: _*) def bind(prefix: String, vals: BindParam*): NodeSeq = bind(prefix, _defaultHtml, vals: _*)


/** /**
* A helper for binding which uses the defaultXml propert and the * A helper for binding which uses the defaultHtml property and the
* default prefix. * default prefix.
*/ */
def bind(vals: BindParam*): NodeSeq = bind(_defaultPrefix, vals: _*) def bind(vals: BindParam*): NodeSeq = bind(_defaultPrefix, vals: _*)
Expand All @@ -995,7 +995,7 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
* take over the screen real estate until the question is answered. * take over the screen real estate until the question is answered.
*/ */
protected def ask(who: LiftCometActor, what: Any)(answerWith: Any => Unit) { protected def ask(who: LiftCometActor, what: Any)(answerWith: Any => Unit) {
who.callInitCometActor(theSession, Full(who.uniqueId), name, defaultXml, attributes) who.callInitCometActor(theSession, Full(who.uniqueId), name, defaultHtml, attributes)
theSession.addCometActor(who) theSession.addCometActor(who)
// who.link(this) // who.link(this)
who ! PerformSetupComet who ! PerformSetupComet
Expand All @@ -1019,7 +1019,7 @@ trait CometActor extends LiftActor with LiftCometActor with BindHelpers {
* rendering. * rendering.
*/ */
protected implicit def nsToNsFuncToRenderOut(f: NodeSeq => NodeSeq) = protected implicit def nsToNsFuncToRenderOut(f: NodeSeq => NodeSeq) =
new RenderOut((Box !! defaultXml).map(f), fixedRender, if (autoIncludeJsonCode) Full(jsonToIncludeInCode & S.jsToAppend()) else { new RenderOut((Box !! defaultHtml).map(f), fixedRender, if (autoIncludeJsonCode) Full(jsonToIncludeInCode & S.jsToAppend()) else {
S.jsToAppend match { S.jsToAppend match {
case Nil => Empty case Nil => Empty
case x :: Nil => Full(x) case x :: Nil => Full(x)
Expand Down
64 changes: 57 additions & 7 deletions web/webkit/src/main/scala/net/liftweb/http/WiringUI.scala
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010 WorldWide Conferencing, LLC * Copyright 2010-2011 WorldWide Conferencing, LLC
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
Expand All @@ -14,13 +14,15 @@
* limitations under the License. * limitations under the License.
*/ */


package net.liftweb { package net.liftweb
package http { package http

import common._
import util._


import _root_.net.liftweb.util._
import js._ import js._
import JsCmds._ import JsCmds._
import _root_.scala.xml.{NodeSeq, Elem, Text} import scala.xml.{NodeSeq, Elem, Text}


/** /**
* Surface a user interface on top of Wiring * Surface a user interface on top of Wiring
Expand Down Expand Up @@ -118,6 +120,23 @@ object WiringUI {
*/ */
def toNode[T](in: NodeSeq, cell: Cell[T])(f: (T, NodeSeq) => NodeSeq): NodeSeq = toNode(in, cell, (id, first, js) => js)(f) def toNode[T](in: NodeSeq, cell: Cell[T])(f: (T, NodeSeq) => NodeSeq): NodeSeq = toNode(in, cell, (id, first, js) => js)(f)


def history[T](cell: Cell[T])(f: (Box[T], T, NodeSeq) => JsCmd): NodeSeq => NodeSeq =
in => {
val myElem: Elem = in.find {
case e: Elem => true
case _ => false
}.map(_.asInstanceOf[Elem]).getOrElse(<span id={Helpers.nextFuncName}>{in}</span>)


addHistJsFunc(cell, (old: Box[T], nw: T) => f(old, nw, in))

new Elem(myElem.prefix,
myElem.label,
myElem.attributes,
myElem.scope)
}


/** /**
* Given a NodeSeq, a Cell and a function that can generate * Given a NodeSeq, a Cell and a function that can generate
* a NodeSeq from the cell's value and the template value, register the * a NodeSeq from the cell's value and the template value, register the
Expand Down Expand Up @@ -299,6 +318,39 @@ object WiringUI {
} else Noop } else Noop
}) })
} }


/**
* Associate a Cell and a function that converts from the
* cell's value to a JavaScript command to be sent to the
* browser as part of the page's post-processing.
*
* @param cell the cell to associate the JavaScript to
* @param f the function that takes the cell's value and a flag indicating
* if this is the first time
*/
def addHistJsFunc[T](cell: Cell[T], f: (Box[T], T) => JsCmd) {
for {
cometActor <- S.currentCometActor
} cell.addDependent(cometActor)

val trc = TransientRequestCell(cell)
var lastTime: Long = 0L
var lastValue: Box[T] = Empty
for {
sess <- S.session
} sess.addPostPageJavaScript(() => {
val (value, ct) = trc.get
val first = lastTime == 0L
if (first || (ct > lastTime && Full(value) != lastValue)) {
val oldValue = lastValue
lastValue = Full(value)
lastTime = ct
f(oldValue, value)
} else Noop
})
}

} }


/** /**
Expand All @@ -308,5 +360,3 @@ private final case class TransientRequestCell[T](cell: Cell[T]) extends Transien
override val __nameSalt = Helpers.nextFuncName override val __nameSalt = Helpers.nextFuncName
} }


}
}

0 comments on commit 3927fcc

Please sign in to comment.