Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Started to merge in 210

  • Loading branch information...
commit 7bebed64f8e5b5bc4a24d8792e09322311f055fc 2 parents c955de1 + 3e95960
@hjast hjast authored
Showing with 320 additions and 83 deletions.
  1. +13 −10 core/util/src/main/scala/net/liftweb/util/SoftReferenceCache.scala
  2. +6 −6 core/util/src/main/scala/net/liftweb/util/TimeHelpers.scala
  3. +28 −0 core/util/src/test/scala/net/liftweb/util/SoftReferenceCacheSpec.scala
  4. +1 −0  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoRecord.scala
  5. +16 −11 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/JObjectField.scala
  6. +9 −0 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
  7. +22 −0 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpec.scala
  8. +4 −6 persistence/record/src/main/scala/net/liftweb/record/ProtoUser.scala
  9. +9 −5 persistence/record/src/main/scala/net/liftweb/record/field/DateTimeField.scala
  10. +4 −2 persistence/record/src/main/scala/net/liftweb/record/field/EmailField.scala
  11. +13 −8 persistence/record/src/main/scala/net/liftweb/record/field/PostalCodeField.scala
  12. +65 −2 persistence/record/src/test/scala/net/liftweb/record/FieldSpec.scala
  13. +21 −6 persistence/record/src/test/scala/net/liftweb/record/Fixtures.scala
  14. +3 −2 project/Dependencies.scala
  15. +3 −8 web/webkit/src/main/scala/net/liftweb/http/LiftServlet.scala
  16. +7 −10 web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala
  17. +9 −1 web/webkit/src/main/scala/net/liftweb/http/S.scala
  18. +18 −3 web/webkit/src/main/scala/net/liftweb/http/SHtml.scala
  19. +1 −1  web/webkit/src/main/scala/net/liftweb/http/js/ScriptRenderer.scala
  20. +2 −2 web/webkit/src/main/scala/net/liftweb/sitemap/Menu.scala
  21. +66 −0 web/webkit/src/test/scala/net/liftweb/http/HtmlPropertiesSpec.scala
View
23 core/util/src/main/scala/net/liftweb/util/SoftReferenceCache.scala
@@ -119,27 +119,30 @@ class SoftReferenceCache[K, V](cacheSize: Int) {
* @return Box[V]
*/
def apply(key: K): Box[V] = {
- val (doRemove:Boolean, retval:Box[V]) =
+ val result:(Boolean,Box[V]) /* (doRemove, retval) */ =
lock(readLock) {
Box.!!(cache.get(key)) match {
case Full(value) =>
- Box.!!(value.get).map((false, _)) openOr {
+ Box.!!(value.get).map(value => (false, Full(value))) openOr {
(true, Empty)
}
case _ => (false, Empty)
}
}
- if (doRemove) {
- lock(writeLock) {
- val value = cache.get(key)
+ result match {
+ case (doRemove, retval) if doRemove =>
+ lock(writeLock) {
+ val value = cache.get(key)
- if (value != null && value.get == null)
- remove(key)
- }
- }
+ if (value != null && value.get == null)
+ remove(key)
+ }
- retval
+ retval
+ case (_, retval) =>
+ retval
+ }
}
/**
View
12 core/util/src/main/scala/net/liftweb/util/TimeHelpers.scala
@@ -89,7 +89,7 @@ trait TimeHelpers { self: ControlHelpers =>
class TimeSpan(private val dt: Either[DateTime, Period]) extends ConvertableToDate {
/** @return a Date as the amount of time represented by the TimeSpan after the Epoch date */
- def this(ms: Long) =
+ def this(ms: Long) =
this(if (ms < 52L * 7L * 24L * 60L * 60L * 1000L) Right(new Period(ms))
else Left(new DateTime(ms)))
@@ -102,7 +102,7 @@ trait TimeHelpers { self: ControlHelpers =>
* Convert to a Date
*/
def toDate: Date = date
-
+
/**
* Convert to a JodaTime DateTime
*/
@@ -117,7 +117,7 @@ trait TimeHelpers { self: ControlHelpers =>
case Left(datetime) => datetime.getMillis()
case Right(duration) => duration.toStandardDuration.getMillis()
}
-
+
/** @return a Date as the amount of time represented by the TimeSpan after now */
def later: TimeSpan = dt match {
@@ -397,12 +397,12 @@ trait TimeHelpers { self: ControlHelpers =>
ret
}
- /** @return a date from a string using the internet format. Return the Epoch date if the parse is unsuccesfull */
+ /** @return a Box[date] from a string using the internet format. */
def boxParseInternetDate(dateString: String): Box[Date] = tryo {
internetDateFormatter.parse(dateString)
}
- /** @return a date from a string using the internet format. Return the Epoch date if the parse is unsuccesfull */
+ /** @return a date from a string using the internet format. Return the Epoch date if the parse is unsuccesful */
def parseInternetDate(dateString: String): Date = tryo {
internetDateFormatter.parse(dateString)
} openOr new Date(0L)
@@ -447,6 +447,6 @@ object ConvertableToDate {
implicit def toDate(in: ConvertableToDate): Date = in.toDate
implicit def toDateTime(in: ConvertableToDate): DateTime = in.toDateTime
implicit def toMillis(in: ConvertableToDate): Long = in.millis
-
+
}
View
28 core/util/src/test/scala/net/liftweb/util/SoftReferenceCacheSpec.scala
@@ -0,0 +1,28 @@
+package net.liftweb.util
+
+import org.specs2.mutable._
+import net.liftweb.common._
+import org.specs2.specification.AroundExample
+
+object SoftReferenceCacheSpec extends Specification {
+
+ sequential
+
+ object cache extends SoftReferenceCache[String, String](1)
+
+ "SoftReferenceCache " should {
+ "Accept additions" in {
+ cache += ("test" -> "test")
+ cache.keys.size() must_== 1
+ }
+ "Allow objects to be retrieved" in {
+ val cached = cache("test")
+ cached must beLike { case Full("test") => ok }
+ }
+ "Properly age out entries" in {
+ cache += ("test2" -> "test2")
+ cache("test") must_== Empty
+ }
+ }
+
+}
View
1  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoRecord.scala
@@ -96,6 +96,7 @@ trait MongoRecord[MyType <: MongoRecord[MyType]] extends BsonRecord[MyType] {
/**
* Mix this into a Record to add an ObjectIdField
*/
+@deprecated("Use one of the MongoPK traits instead", "2.5")
trait MongoId[OwnerType <: MongoRecord[OwnerType]] {
self: OwnerType =>
View
27 ...istence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/JObjectField.scala
@@ -19,23 +19,28 @@ package mongodb
package record
package field
-import common.{Box, Empty, Failure, Full}
-import http.js.JE.Str
-import json.JsonAST.{JNothing, JObject, JValue}
-import json.JsonParser
-import net.liftweb.record.{Field, MandatoryTypedField, Record}
+import common._
+import http.js.JE._
+import json._
+import util.Helpers.tryo
+import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField, Record}
import scala.xml.NodeSeq
class JObjectField[OwnerType <: Record[OwnerType]](rec: OwnerType) extends Field[JObject, OwnerType] with MandatoryTypedField[JObject] {
- def asJs = Str(toString)
-
- def asJValue = (JNothing: JValue) // not implemented
+ def asJs = asJValue match {
+ case JNothing => JsNull
+ case jv => JsRaw(compact(render(jv)))
+ }
- def setFromJValue(jvalue: JValue) = Empty // not implemented
+ def asJValue = valueBox openOr (JNothing: JValue)
- def asXHtml = <div></div>
+ def setFromJValue(jvalue: JValue): Box[JObject] = jvalue match {
+ case JNothing|JNull if optional_? => setBox(Empty)
+ case jo: JObject => setBox(Full(jo))
+ case other => setBox(FieldHelpers.expectedA("JObject", other))
+ }
def defaultValue = JObject(List())
@@ -54,7 +59,7 @@ class JObjectField[OwnerType <: Record[OwnerType]](rec: OwnerType) extends Field
// assume string is json
def setFromString(in: String): Box[JObject] = {
// use lift-json to parse string into a JObject
- Full(set(JsonParser.parse(in).asInstanceOf[JObject]))
+ setBox(tryo(JsonParser.parse(in).asInstanceOf[JObject]))
}
def toForm: Box[NodeSeq] = Empty
View
9 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
@@ -485,3 +485,12 @@ class RefFieldTestRecord private () extends MongoRecord[RefFieldTestRecord] with
object RefFieldTestRecord extends RefFieldTestRecord with MongoMetaRecord[RefFieldTestRecord] {
override def formats = allFormats
}
+
+
+class JObjectFieldTestRecord private () extends Record[JObjectFieldTestRecord] {
+ def meta = JObjectFieldTestRecord
+
+ object mandatoryJObjectField extends JObjectField(this)
+}
+
+object JObjectFieldTestRecord extends JObjectFieldTestRecord with MetaRecord[JObjectFieldTestRecord]
View
22 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpec.scala
@@ -473,5 +473,27 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
)
}
}
+
+ "JObjectField" should {
+ val jo: JValue = ("minutes" -> 59)
+ val json: JObject = ("mandatoryJObjectField" -> jo)
+
+ "convert to JValue" in {
+ val rec = JObjectFieldTestRecord.createRecord
+ .mandatoryJObjectField(json)
+
+ rec.mandatoryJObjectField.asJValue must_== json
+
+ }
+ "get set from JValue" in {
+ val fromJson = JObjectFieldTestRecord.fromJValue(json)
+
+ fromJson.isDefined must_== true
+ fromJson foreach { r =>
+ r.asJValue must_== json
+ }
+ success
+ }
+ }
}
View
10 persistence/record/src/main/scala/net/liftweb/record/ProtoUser.scala
@@ -33,8 +33,7 @@ import net.liftweb.record.field._
import net.liftweb.proto.{ProtoUser => GenProtoUser}
/**
- * ProtoUser is a base class that gives you a "User" that has a first name,
- * last name, email, etc.
+ * ProtoUser provides a "User" with a first name, last name, email, etc.
*/
trait ProtoUser[T <: ProtoUser[T]] extends Record[T] {
self: T =>
@@ -177,7 +176,7 @@ trait ProtoUser[T <: ProtoUser[T]] extends Record[T] {
}
/**
- * Mix this trait into the the Mapper singleton for User and you
+ * Mix this trait into the Mapper singleton for User and you
* get a bunch of user functionality including password reset, etc.
*/
trait MetaMegaProtoUser[ModelType <: MegaProtoUser[ModelType]] extends MetaRecord[ModelType] with GenProtoUser {
@@ -203,7 +202,7 @@ trait MetaMegaProtoUser[ModelType <: MegaProtoUser[ModelType]] extends MetaRecor
def displayHtml: NodeSeq = from.displayHtml
/**
- * Does this represent a pointer to a Password field
+ * Does this represent a pointer to a Password field?
*/
def isPasswordField_? : Boolean = from match {
case a: PasswordField[_] => true
@@ -366,7 +365,7 @@ trait MegaProtoUser[T <: MegaProtoUser[T]] extends ProtoUser[T] {
}
/**
- * The has the user been validated.
+ * Whether the user has been validated.
* You can override the behavior
* of this field:
* <pre name="code" class="scala">
@@ -427,4 +426,3 @@ trait MegaProtoUser[T <: MegaProtoUser[T]] extends ProtoUser[T] {
def localeDisplayName = S.?("locale")
}
-
View
14 persistence/record/src/main/scala/net/liftweb/record/field/DateTimeField.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.
@@ -22,7 +22,7 @@ import scala.xml._
import net.liftweb.common._
import net.liftweb.http.{S}
import net.liftweb.http.js._
-import net.liftweb.json.JsonAST.JValue
+import net.liftweb.json._
import net.liftweb.util._
import java.util.{Calendar, Date}
import Helpers._
@@ -36,6 +36,10 @@ trait DateTimeTypedField extends TypedField[Calendar] {
cal
}
+ val formats = new DefaultFormats {
+ override def dateFormatter = Helpers.internetDateFormatter
+ }
+
def setFromAny(in : Any): Box[Calendar] = toDate(in).flatMap(d => setBox(Full(dateToCal(d)))) or genericSetFromAny(in)
def setFromString(s: String): Box[Calendar] = s match {
@@ -57,11 +61,11 @@ trait DateTimeTypedField extends TypedField[Calendar] {
case _ => Full(elem)
}
- def asJs = valueBox.map(v => Str(toInternetDate(v.getTime))) openOr JsNull
+ def asJs = valueBox.map(v => Str(formats.dateFormat.format(v.getTime))) openOr JsNull
- def asJValue = asJString(v => toInternetDate(v.getTime))
+ def asJValue = asJString(v => formats.dateFormat.format(v.getTime))
def setFromJValue(jvalue: JValue) = setFromJString(jvalue) {
- v => boxParseInternetDate(v).map(d => {
+ v => formats.dateFormat.parse(v).map(d => {
val cal = Calendar.getInstance
cal.setTime(d)
cal
View
6 persistence/record/src/main/scala/net/liftweb/record/field/EmailField.scala
@@ -34,14 +34,16 @@ object EmailField {
}
trait EmailTypedField extends TypedField[String] {
- private def validateEmail(emailValue: ValueType): List[FieldError] =
+ private def validateEmail(emailValue: ValueType): List[FieldError] = {
toBoxMyType(emailValue) match {
+ case Full(email) if (optional_? && email.isEmpty) => Nil
case Full(email) if EmailField.validEmailAddr_?(email) => Nil
case _ => Text(S.?("invalid.email.address"))
}
+ }
override def validations = validateEmail _ :: Nil
-}
+}
class EmailField[OwnerType <: Record[OwnerType]](rec: OwnerType, maxLength: Int)
extends StringField[OwnerType](rec, maxLength) with EmailTypedField
View
21 persistence/record/src/main/scala/net/liftweb/record/field/PostalCodeField.scala
@@ -29,21 +29,26 @@ import S._
trait PostalCodeTypedField extends StringTypedField {
-
+
protected val country: CountryField[_]
override def setFilter = toUpper _ :: trim _ :: super.setFilter
override def validations = validatePostalCode _ :: Nil
- def validatePostalCode(in: ValueType): List[FieldError] = country.value match {
- case Countries.USA => valRegex(RegexPattern.compile("[0-9]{5}(\\-[0-9]{4})?"), S.?("invalid.zip.code"))(in)
- case Countries.Sweden => valRegex(RegexPattern.compile("[0-9]{3}[ ]?[0-9]{2}"), S.?("invalid.postal.code"))(in)
- case Countries.Australia => valRegex(RegexPattern.compile("(0?|[1-9])[0-9]{3}"), S.?("invalid.postal.code"))(in)
- case Countries.Canada => valRegex(RegexPattern.compile("[A-Z][0-9][A-Z][ ][0-9][A-Z][0-9]"), S.?("invalid.postal.code"))(in)
- case _ => genericCheck(in)
+ def validatePostalCode(in: ValueType): List[FieldError] = {
+ toBoxMyType(in) match {
+ case Full(zip) if (optional_? && zip.isEmpty) => Nil
+ case _ =>
+ country.value match {
+ case Countries.USA => valRegex(RegexPattern.compile("[0-9]{5}(\\-[0-9]{4})?"), S.?("invalid.zip.code"))(in)
+ case Countries.Sweden => valRegex(RegexPattern.compile("[0-9]{3}[ ]?[0-9]{2}"), S.?("invalid.postal.code"))(in)
+ case Countries.Australia => valRegex(RegexPattern.compile("(0?|[1-9])[0-9]{3}"), S.?("invalid.postal.code"))(in)
+ case Countries.Canada => valRegex(RegexPattern.compile("[A-Z][0-9][A-Z][ ][0-9][A-Z][0-9]"), S.?("invalid.postal.code"))(in)
+ case _ => genericCheck(in)
+ }
+ }
}
-
private def genericCheck(zip: ValueType): List[FieldError] = {
toBoxMyType(zip) flatMap {
case null => Full(Text(S.?("invalid.postal.code")))
View
67 persistence/record/src/test/scala/net/liftweb/record/FieldSpec.scala
@@ -49,9 +49,9 @@ object FieldSpec extends Specification {
!mandatory.defaultValue.isInstanceOf[Calendar] // don't try to use the default value of date/time typed fields, because it changes from moment to moment!
def commonBehaviorsForMandatory(in: MandatoryTypedField[A]): Unit = {
-
+
if (canCheckDefaultValues) {
- "which have the correct initial value" in S.initIfUninitted(session) {
+ "which have the correct initial value" in S.initIfUninitted(session) {
in.get must_== in.defaultValue
}
}
@@ -326,6 +326,19 @@ object FieldSpec extends Specification {
)
}
+ "DateTimeField with custom format" should {
+ val rec = CustomFormatDateTimeRecord.createRecord
+ val dt = Calendar.getInstance
+ val dtStr = rec.customFormatDateTimeField.formats.dateFormat.format(dt.getTime)
+ passConversionTests(
+ dt,
+ rec.customFormatDateTimeField,
+ Str(dtStr),
+ JString(dtStr),
+ Full(<input name=".*" type="text" tabindex="1" value={toInternetDate(dt.getTime)} id="customFormatDateTimeField_id"></input>)
+ )
+ }
+
"DecimalField" should {
val rec = FieldTypeTestRecord.createRecord
val bd = BigDecimal("12.34")
@@ -353,6 +366,7 @@ object FieldSpec extends Specification {
}
"EmailField" should {
+ val session = new LiftSession("", randomString(20), Empty)
val rec = FieldTypeTestRecord.createRecord
val email = "foo@bar.baz"
passBasicTests(email, rec.mandatoryEmailField, rec.legacyOptionalEmailField, rec.optionalEmailField)
@@ -363,6 +377,30 @@ object FieldSpec extends Specification {
JString(email),
Full(<input name=".*" type="text" maxlength="100" tabindex="1" value={email} id="mandatoryEmailField_id"></input>)
)
+ "pass validation if field is optional and value is Empty" in {
+ S.initIfUninitted(session) {
+ rec.legacyOptionalEmailField(Empty)
+ rec.legacyOptionalEmailField.validate must have length(0)
+
+ rec.optionalEmailField(Empty)
+ rec.optionalEmailField.validate must have length(0)
+ }
+ }
+ "pass validation if field is optional and value is an empty string" in {
+ S.initIfUninitted(session) {
+ rec.legacyOptionalEmailField("")
+ rec.legacyOptionalEmailField.validate must have length(0)
+
+ rec.optionalEmailField("")
+ rec.optionalEmailField.validate must have length(0)
+ }
+ }
+ "fail validation if value is invalid" in {
+ S.initIfUninitted(session) {
+ rec.mandatoryEmailField("invalid email")
+ rec.mandatoryEmailField.validate must have length(1)
+ }
+ }
}
"EnumField" should {
@@ -444,6 +482,7 @@ object FieldSpec extends Specification {
}
"PostalCodeField" should {
+ val session = new LiftSession("", randomString(20), Empty)
val rec = FieldTypeTestRecord.createRecord
val zip = "02452"
rec.mandatoryCountryField.set(Countries.USA)
@@ -455,6 +494,30 @@ object FieldSpec extends Specification {
JString(zip),
Full(<input name=".*" type="text" maxlength="32" tabindex="1" value={zip} id="mandatoryPostalCodeField_id"></input>)
)
+ "pass validation if field is optional and value is Empty" in {
+ S.initIfUninitted(session) {
+ rec.legacyOptionalPostalCodeField(Empty)
+ rec.legacyOptionalPostalCodeField.validate must have length(0)
+
+ rec.optionalPostalCodeField(Empty)
+ rec.optionalPostalCodeField.validate must have length(0)
+ }
+ }
+ "pass validation if field is optional and value is an empty string" in {
+ S.initIfUninitted(session) {
+ rec.legacyOptionalPostalCodeField("")
+ rec.legacyOptionalPostalCodeField.validate must have length(0)
+
+ rec.optionalPostalCodeField("")
+ rec.optionalPostalCodeField.validate must have length(0)
+ }
+ }
+ "fail validation if value is invalid" in {
+ S.initIfUninitted(session) {
+ rec.mandatoryPostalCodeField("invalid zip")
+ rec.mandatoryPostalCodeField.validate must have length(1)
+ }
+ }
}
"StringField" should {
View
27 persistence/record/src/test/scala/net/liftweb/record/Fixtures.scala
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2011 WorldWide Conferencing, LLC
+ * Copyright 2010-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.
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-package net.liftweb
-package record
-package fixtures
+package net.liftweb
+package record
+package fixtures
import java.math.MathContext
import scala.xml.Text
import common.{Box, Empty, Full}
+import json._
import util.{FieldError, Helpers}
import org.specs2.mutable._
@@ -45,7 +46,7 @@ class PasswordTestRecord private () extends Record[PasswordTestRecord] {
override def validations = validateNonEmptyPassword _ ::
super.validations
- def validateNonEmptyPassword(v: String): List[FieldError] =
+ def validateNonEmptyPassword(v: String): List[FieldError] =
v match {
case "testvalue" => Text("no way!")
case _ => Nil
@@ -238,7 +239,7 @@ object FieldTypeTestRecord extends FieldTypeTestRecord with MetaRecord[FieldType
trait SyntheticTestTrait{
val genericField: StringField[_]
-
+
}
class SyntheticTestRecord extends Record[SyntheticTestRecord] with SyntheticTestTrait{
@@ -251,3 +252,17 @@ class SyntheticTestRecord extends Record[SyntheticTestRecord] with SyntheticTest
object SyntheticTestRecord extends SyntheticTestRecord with MetaRecord[SyntheticTestRecord]
+class CustomFormatDateTimeRecord private () extends Record[CustomFormatDateTimeRecord] {
+ import java.text.SimpleDateFormat
+
+ def meta = CustomFormatDateTimeRecord
+
+ object customFormatDateTimeField extends DateTimeField(this) {
+ override val formats = new DefaultFormats {
+ override def dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
+ }
+ }
+
+}
+
+object CustomFormatDateTimeRecord extends CustomFormatDateTimeRecord with MetaRecord[CustomFormatDateTimeRecord]
View
5 project/Dependencies.scala
@@ -47,8 +47,9 @@ object Dependencies {
lazy val scala_compiler: ModuleMap = "org.scala-lang" % "scala-compiler" % _
lazy val scalaz_core: ModuleMap = sv => scalazGroup(sv) % "scalaz-core" % scalazVersion(sv) cross CVMappingAll
lazy val slf4j_api = "org.slf4j" % "slf4j-api" % slf4jVersion
- lazy val squeryl = "org.squeryl" % "squeryl" % "0.9.5-1" cross crossMapped("2.9.1-1" -> "2.9.1", "2.8.2" -> "2.8.1")
- @deprecated lazy val scalaactors= {v: String => "org.scala-lang" % "scala-actors" % v }
+
+ lazy val squeryl = "org.squeryl" % "squeryl" % "0.9.5-4" cross crossMapped("2.9.1-1" -> "2.9.1", "2.8.2" -> "2.8.1")
+
// Aliases
lazy val mongo_driver = mongo_java_driver
View
11 web/webkit/src/main/scala/net/liftweb/http/LiftServlet.scala
@@ -415,13 +415,6 @@ class LiftServlet extends Loggable {
toReturn
}
- private def extractVersion[T](path: List[String])(f: => T): T = {
- path match {
- case first :: second :: _ => RenderVersion.doWith(second)(f)
- case _ => f
- }
- }
-
/**
* Tracks the two aspects of an AJAX version: the sequence number,
* whose sole purpose is to identify requests that are retries for the
@@ -456,8 +449,10 @@ class LiftServlet extends Loggable {
*/
private def extractVersions[T](path: List[String])(f: (Box[AjaxVersionInfo]) => T): T = {
path match {
- case first :: AjaxVersions(versionInfo @ AjaxVersionInfo(renderVersion, _, _)) :: _ =>
+ case ajaxPath :: AjaxVersions(versionInfo @ AjaxVersionInfo(renderVersion, _, _)) :: _ =>
RenderVersion.doWith(renderVersion)(f(Full(versionInfo)))
+ case ajaxPath :: renderVersion :: _ =>
+ RenderVersion.doWith(renderVersion)(f(Empty))
case _ => f(Empty)
}
}
View
17 web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala
@@ -433,7 +433,7 @@ private[http] object RenderVersion {
}
/**
- * A trait defining how stateful the session is
+ * A trait defining how stateful the session is
*/
trait HowStateful {
private val howStateful = new ThreadGlobal[Boolean]
@@ -527,13 +527,10 @@ private[http] final case class AjaxRequestInfo(requestVersion: Long,
*/
class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
val httpSession: Box[HTTPSession]) extends LiftMerge with Loggable with HowStateful {
- val sessionHtmlProperties: SessionVar[HtmlProperties] =
- new SessionVar[HtmlProperties](LiftRules.htmlProperties.vend(
- S.request openOr Req.nil
- )) {}
+ def sessionHtmlProperties = LiftRules.htmlProperties.session.is.make openOr LiftRules.htmlProperties.default.is.vend
val requestHtmlProperties: TransientRequestVar[HtmlProperties] =
- new TransientRequestVar[HtmlProperties](sessionHtmlProperties.is) {}
+ new TransientRequestVar[HtmlProperties](sessionHtmlProperties(S.request openOr Req.nil)) {}
@volatile
private[http] var markedForTermination = false
@@ -635,7 +632,7 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
lastServiceTime = millis
LiftSession.onSetupSession.foreach(_(this))
- sessionHtmlProperties.is // cause the properties to be calculated
+ sessionHtmlProperties // cause the properties to be calculated
}
def running_? = _running_?
@@ -1670,7 +1667,7 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
val ret = findSnippetInstance(nameToTry)
// Update the snippetMap so that we reuse the same instance in this request (unless the snippet is transient)
ret.filter(TransientSnippet.notTransient(_)).foreach(s => snippetMap.set(snippetMap.is.updated(tagName, s)))
-
+
ret
}
}
@@ -1696,7 +1693,7 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
runWhitelist(snippet, cls, method, kids){(S.locateMappedSnippet(snippet).map(_(kids)) or
locSnippet(snippet)).openOr(
S.locateSnippet(snippet).map(_(kids)) openOr {
-
+
(locateAndCacheSnippet(cls)) match {
// deal with a stateless request when a snippet has
// different behavior in stateless mode
@@ -1838,7 +1835,7 @@ class LiftSession(private[http] val _contextPath: String, val uniqueId: String,
e.snippetFailure,
e.buildStackTrace,
wholeTag)
-
+
case e: SnippetFailureException =>
reportSnippetError(page, snippetName,
e.snippetFailure,
View
10 web/webkit/src/main/scala/net/liftweb/http/S.scala
@@ -933,10 +933,18 @@ trait S extends HasParams with Loggable {
* If you do not define an entry for a particular key, we fall back to using
* Lift's core entries.
*
+ * We cache the values in modes other than DevMode
+ *
* @see LiftRules.resourceNames
* @see LiftRules.resourceBundleFactories
*/
- def resourceBundles: List[ResourceBundle] = resourceBundles(locale) ++ liftCoreResourceBundle.toList
+ def _resourceBundles: List[ResourceBundle] = resourceBundles(locale) ++ liftCoreResourceBundle.toList
+
+ private lazy val cachedResourceBundles = _resourceBundles
+
+ private def resourceBundles: List[ResourceBundle] =
+ if (Props.devMode) _resourceBundles else cachedResourceBundles
+
def resourceBundles(loc: Locale): List[ResourceBundle] = {
_resBundle.box match {
View
21 web/webkit/src/main/scala/net/liftweb/http/SHtml.scala
@@ -199,6 +199,21 @@ trait SHtml {
/**
+ * Build a JavaScript function that will perform a JSON call based on a value calculated in JavaScript.
+ *
+ * The JSON generated by func will be returned to the client and passed as argument to the javascript function specified in
+ * jsonContext.success
+ *
+ * @param jsCalcValue the JavaScript to calculate the value to be sent to the server
+ * @param jsonContext the context instance that defines JavaScript to be executed on call success or failure
+ * @param func the function to call when the JSON data is sent. The returned JSON is sent back to the client
+ *
+ * @return the function ID and JavaScript that makes the call
+ */
+ def jsonCall(jsCalcValue: JsExp, jsonContext: JsonContext, func: JsonAST.JValue => JsonAST.JValue): GUIDJsExp =
+ jsonCall_*(jsCalcValue, jsonContext, S.SFuncHolder(s => parseOpt(s).map(func) getOrElse JsonAST.JNothing))
+
+ /**
* Build a JavaScript function that will perform a JSON call based on a value calculated in JavaScript
*
* @param jsCalcValue the JavaScript to calculate the value to be sent to the server
@@ -254,9 +269,9 @@ trait SHtml {
f(name, js)
}
- def jsonCall(jsCalcValue: JsExp,
- jsonContext: JsonContext,
- func: String => JsObj): GUIDJsExp = ajaxCall_*(jsCalcValue, jsonContext, SFuncHolder(func))
+ @deprecated("Use jsonCall with a function that takes JValue => JValue", "2.5")
+ def jsonCall(jsCalcValue: JsExp, jsonContext: JsonContext, func: String => JsObj)(implicit d: AvoidTypeErasureIssues1): GUIDJsExp =
+ ajaxCall_*(jsCalcValue, jsonContext, SFuncHolder(func))
def fjsonCall[T](jsCalcValue: JsExp, jsonContext: JsonContext, func: String => JsObj)(f: (String, JsExp) => T): T = {
val (name, js) = jsonCall(jsCalcValue, jsonContext, func).product
View
2  web/webkit/src/main/scala/net/liftweb/http/js/ScriptRenderer.scala
@@ -196,7 +196,7 @@ object ScriptRenderer {
""" + {
if (LiftRules.enableLiftGC) { """
var replacement = '""" + LiftRules.ajaxPath + """/'+lift_page;
- if (version)
+ if (version!=null)
replacement += ('-'+version.toString(36)) + (liftAjax.lift_ajaxQueue.length > 35 ? 35 : liftAjax.lift_ajaxQueue.length).toString(36);
return url.replace('""" + LiftRules.ajaxPath + """', replacement);"""
} else {
View
4 web/webkit/src/main/scala/net/liftweb/sitemap/Menu.scala
@@ -555,9 +555,9 @@ sealed trait MenuSingleton {
/**
* A convenient way to define a Menu items that's got the same name as it does it's localized LinkText.
- * <pre>Menu.i("Home") / "index"</pre> is short-hand for <pre>Menu("Home", S ? "Home") / "index"</pre>
+ * <pre>Menu.i("Home") / "index"</pre> is short-hand for <pre>Menu("Home", S.loc("Home", Text("Home")) / "index"</pre>
*/
- def i(nameAndLink: String): PreMenu = Menu.apply(nameAndLink, S ? nameAndLink)
+ def i(nameAndLink: String): PreMenu = Menu.apply(nameAndLink, S.loc(nameAndLink, scala.xml.Text(nameAndLink)))
def param[T<:AnyRef](name: String, linkText: Loc.LinkText[T], parser: String => Box[T],
encoder: T => String): PreParamMenu[T] =
View
66 web/webkit/src/test/scala/net/liftweb/http/HtmlPropertiesSpec.scala
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011 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 http
+
+import mockweb._
+
+
+import scala.xml.NodeSeq
+
+import common.{ Box, Empty, Full }
+
+/**
+* This only exists to keep the WebSpecSpec clean. Normally,
+* you could just use "() => bootstrap.Boot.boot".
+*/
+object HtmlPropertiesSpecBoot {
+ def boot() {
+ LiftRules.htmlProperties.default.set((_: Req) match {
+ case r @ Req("html5" :: _, _, _) =>
+ println("Html5 request: " + r)
+ Html5Properties(r.userAgent)
+ case r =>
+ println("other request: " + r)
+ OldHtmlProperties(r.userAgent)
+ })
+ }
+}
+
+class HtmlPropertiesSpec extends WebSpec(HtmlPropertiesSpecBoot.boot _) {
+ sequential
+
+ "LiftRules.htmlProperties.default function" should {
+ val testUrl1 = "http://example.com/html5/something"
+ val testUrl2 = "http://example.com/anotherurl"
+
+ val session1 = MockWeb.testS(testUrl1)(S.session)
+ val session2 = MockWeb.testS(testUrl2)(S.session)
+
+ "set S.htmlProperties to html5 when that is the first request" withSFor(testUrl1, session1) in {
+ S.htmlProperties must haveClass[Html5Properties]
+ }
+ "set S.htmlProperties to xhtml when that is not the first request" withSFor(testUrl2, session1) in {
+ S.htmlProperties must haveClass[OldHtmlProperties]
+ }
+ "set S.htmlProperties to xhtml when that is the first request" withSFor(testUrl2, session2) in {
+ S.htmlProperties must haveClass[OldHtmlProperties]
+ }
+ "set S.htmlProperties to html5 when that is not the first request" withSFor(testUrl1, session2) in {
+ S.htmlProperties must haveClass[Html5Properties]
+ }
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.