- Lift provides powerful facilities to build highly
- interactive web applications.
-
-
- Lift supports Comet-style long polling with very little work on the
- part of the developer. Here's the code the implements the clock
- that you see in this demo:
-
-
-
-
-
-
-class Clock extends CometActor {
- override def defaultPrefix = Full("clk" )
- ActorPing.schedule(this , Tick, 10 seconds)
+
+
+
+
+ Template
+
+
+
+
+ Lift provides powerful facilities to build highly
+ interactive web applications.
+
+
Ajax
+
+ Lift has powerful set of Ajax features that all you to
+ create Ajax controls with as little as 1 line of code:
+
+
ajaxButton("", s => {println("you said: "+s); SetHtml("place", <b>{s}</b>)})
+
+
+
+
Comet
+
+ Lift supports Comet-style long polling with very little work on the
+ part of the developer. Here's the code the implements the clock
+ that you see in this demo:
+
class ExampleClock(initSession: LiftSession,
+ initType: Box[String],
+ initName: Box[String],
+ initDefaultXml: NodeSeq,
+ initAttributes: Map[String, String])
+ extends CometActor {
+ // schedule a ping every 10 seconds so we redraw
+ Schedule.schedule(this, Tick, 10 seconds)
+
+ def render = "#clock_time *" #> Text(now.toString)
+
+ override def lowPriority = {
+ case Tick =>
+ partialUpdate(SetHtml("clock_time", Text(now.toString)))
+ Schedule.schedule(this, Tick, 10 seconds)
+ }
- private lazy val spanId = uniqueId+"_timespan"
+ val creationInfo = new CometCreationInfo(initType.orNull,
+ initName,
+ initDefaultXml,
+ initAttributes,
+ initSession)
- def render = bind("time" -> timeSpan)
+ initCometActor(creationInfo)
+}
- def timeSpan = (<span id={spanId}>{timeNow}</span>)
+case object Tick
-
override def lowPriority = {
-
case Tick =>
- partialUpdate(SetHtml(spanId, Text(timeNow.toString)))
- ActorPing.schedule(
this , Tick, 10 seconds)
- }
-}
-
+
-
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/lazy.html b/combo/example/src/main/webapp/lazy.html
index bc3e0e1..ed2585a 100644
--- a/combo/example/src/main/webapp/lazy.html
+++ b/combo/example/src/main/webapp/lazy.html
@@ -1,95 +1,52 @@
-
+
+
+
+
+ Template
+
+
+
Lift supports lazy loading of a snippet. This is
useful when a snippet may take a long time to render,
but you want to return the page to the browser quickly.
-
-
-
+
-
-
+
-
-
+
-
-
+
+
+
The Markup:
+
<div data-lift="lazy-load">
+ <div data-lift="LongTime"></div>
+ </div>
-
-
-
-
-
The Markup:
-
- <div >
- <lift :lazy-load ><div class ="lift:LongTime" ></div ></lift :lazy-load >
- </div >
-
-
-
The Scala Code:
-
-object LongTime {
- def render = {
- val delay = 1000L + randomLong(10000)
+ The Scala Code:
+ object LongTime {
+ def render = {
+ val delay = 1000L + randomLong(10000)
Thread.sleep(delay)
-
+
<div>
This thread delayed {delay / 1000L} seconds
</div>
}
-}
-
+}
-
+
+
diff --git a/combo/example/src/main/webapp/menu/four.html b/combo/example/src/main/webapp/menu/four.html
index 4e65fbc..c4e12dd 100644
--- a/combo/example/src/main/webapp/menu/four.html
+++ b/combo/example/src/main/webapp/menu/four.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 4
diff --git a/combo/example/src/main/webapp/menu/index.html b/combo/example/src/main/webapp/menu/index.html
index 3e7b0e1..d923127 100644
--- a/combo/example/src/main/webapp/menu/index.html
+++ b/combo/example/src/main/webapp/menu/index.html
@@ -1,3 +1,3 @@
-
+
Main Menu page... note the submenus on the menu bar
diff --git a/combo/example/src/main/webapp/menu/one.html b/combo/example/src/main/webapp/menu/one.html
index 39b3634..3b8b1d7 100644
--- a/combo/example/src/main/webapp/menu/one.html
+++ b/combo/example/src/main/webapp/menu/one.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 1
diff --git a/combo/example/src/main/webapp/menu/three.html b/combo/example/src/main/webapp/menu/three.html
index 832bf09..f4d46dd 100644
--- a/combo/example/src/main/webapp/menu/three.html
+++ b/combo/example/src/main/webapp/menu/three.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 3
diff --git a/combo/example/src/main/webapp/menu/two.html b/combo/example/src/main/webapp/menu/two.html
index 560db3e..9bab16b 100644
--- a/combo/example/src/main/webapp/menu/two.html
+++ b/combo/example/src/main/webapp/menu/two.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 2
diff --git a/combo/example/src/main/webapp/menu/two_one.html b/combo/example/src/main/webapp/menu/two_one.html
index 6d2f9e9..0d7c836 100644
--- a/combo/example/src/main/webapp/menu/two_one.html
+++ b/combo/example/src/main/webapp/menu/two_one.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 2-1
diff --git a/combo/example/src/main/webapp/menu/two_two.html b/combo/example/src/main/webapp/menu/two_two.html
index 03cb015..0b8a243 100644
--- a/combo/example/src/main/webapp/menu/two_two.html
+++ b/combo/example/src/main/webapp/menu/two_two.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 2-2
diff --git a/combo/example/src/main/webapp/templates-hidden/default.html b/combo/example/src/main/webapp/templates-hidden/default.html
index 9efdede..b62c7c2 100644
--- a/combo/example/src/main/webapp/templates-hidden/default.html
+++ b/combo/example/src/main/webapp/templates-hidden/default.html
@@ -6,10 +6,18 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Template
+
-
-class AjaxForm {
- var state = AjaxForm.state
- var city = ""
+
+
+
+ AJAX Form Update
+
+
Choose city and state:
+
+
+ State:
+
+ City:
+
+
+
+
+ Here's the code:
+
+
+class AjaxForm {
+ var state = AjaxForm.state
+ var city = ""
- private def cityChoice (state : String ): Elem = {
- val cities = AjaxForm.citiesFor(state)
- val first = cities.head
- untrustedSelect(cities.map(s => (s,s)), Full(first), city = _)
+ private def cityChoice(state: String): Elem = {
+ val cities = AjaxForm.citiesFor(state)
+ val first = cities.head
+ // make the select "untrusted" because we might put new values
+ // in the select
+ untrustedSelect(cities.map(s => (s, s)), Full(first), s => city = s)
}
- private def replace (state : String ): JsCmd = {
- val cities = AjaxForm.citiesFor(state)
- val first = cities.head
- ReplaceOptions("city_select" , cities.map(s => (s,s)), Full(first))
+ private def replace(state: String): JsCmd = {
+ val cities = AjaxForm.citiesFor(state)
+ val first = cities.head
+ ReplaceOptions("city", cities.map(s => (s, s)), Full(first))
}
-
- def show (xhtml : Group ): NodeSeq = {
- val (name , js ) = ajaxCall(JE.JsRaw("this.value" ),
- s => After(200, replace(s)))
- bind("select" , xhtml,
- "state" -> select(AjaxForm.states.map(s => (s,s)),
- Full(state), state = _, "onchange" -> js.toJsCmd) %
- (new PrefixedAttribute("lift" , "gc" , name, Null)),
- "city" -> cityChoice(state) % ("id" -> "city_select" ),
- "submit" -> submit(?("Save" ),
- () =>
- {S.notice("City: " +city+" State: " +state);
- redirectTo("/" )}))
+ def render = {
+ "#state" #> ajaxSelect(AjaxForm.states.map(s => (s, s)), Full(state), { s =>
+ state = s; After(200, replace(state))
+ }) &
+ "#city" #> cityChoice(state) &
+ "type=submit" #> submit(?("Save"), () => {
+ S.notice("City: " + city + ", State: " + state); redirectTo("/")
+ })
}
}
-
+object AjaxForm {
+ val citiesAndStates = List(
+ "Alabama" -> "Birmingham",
+ "Alabama" -> "Huntsville",
+ :
+ :
+ "Wisconsin" -> "Milwaukee"
+ )
+
+ val states = citiesAndStates.map(_._1).distinct
+
+ val state: String = states.head
+
+ def citiesFor(state: String): List[String] =
+ citiesAndStates.filter(_._1 == state).map(_._2)
+}
+
+
+
+
+
-
-
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/ajax.html b/combo/example/src/main/webapp/ajax.html
index 1c738af..2a44b4d 100644
--- a/combo/example/src/main/webapp/ajax.html
+++ b/combo/example/src/main/webapp/ajax.html
@@ -1,134 +1,158 @@
-
-
- AJAX Samples
-
-
-
- Click me to increase the count (currently 0 )
-
-
-
-
-
-
- You selected From the select box.
-
-
-
-
- You entered in the text box.
-
-
-
-
- An example of autocomplete with a server round trip to
- calculate the autocomplete list
-
-
-
-
-
-
- And each time an Ajax or Comet update is made to the page,
- we update this span:
-
The time is
+
+
+
+
+
Template
+
+
+
+
+
+
+
+
+
+
AJAX Samples
+
+
+
+ Click me to increase the count (currently 0 )
+
+
+
+
+
+
+
+
+
+
+
+
+
+ And each time an Ajax or Comet update is made to the page,
+ we update this span:
+ The time is
+
+
+
+
+
-
-
-
-
- Enter some text:
- and Click Here
-
-
-
-
-
-
- The
Lift Scala code to render the controls:
-
-
-
-
-
-
-class Ajax {
-
- def sample (xhtml : NodeSeq ): NodeSeq = {
- var cnt = 0
-
- val spanName : String = S.attr("id_name" ) openOr "cnt_id"
- val msgName : String = S.attr("id_msgs" ) openOr "messages"
-
- def doClicker (text : NodeSeq ) =
- a(() => {cnt = cnt + 1; SetHtml(spanName, Text( cnt.toString))}, text)
-
- def doSelect (msg : NodeSeq ) =
- ajaxSelect((1 to 50).toList.map(i => (i.toString, i.toString)),
- Full(1.toString),
- v => DisplayMessage(msgName,
- bind("sel" , msg, "number" -> Text(v)),
- 5 seconds, 1 second))
-
- def doText (msg : NodeSeq ) =
- ajaxText("" , v => DisplayMessage(msgName,
- bind("text" , msg, "value" -> Text(v)),
- 4 seconds, 1 second))
-
-
-
- bind("ajax" , xhtml,
- "clicker" -> doClicker _,
- "select" -> doSelect _,
- "text" -> doText _,
- "auto" -> JqSHtml.autocomplete("" , buildQuery _, _ => ()))
+ viewBind(xhtml)
+ }
+
+ private def buildQuery(current: String, limit: Int): Seq[String] = {
+ logger.info(
+ "Checking on server side with " + current + " limit " + limit)
+ (1 to limit).map(n => current + "" + n)
+ }
+
+ def time = Text(now.toString)
+
+ def buttonClick = {
+ import js.JE._
+
+ "* [onclick]" #> SHtml.ajaxCall(
+ ValById("the_input"),
+ s =>
+ SetHtml("bcmessages",
+ <i>Latest Button click was with text box value '{s}'</i>))
+ }
}
+
-
private def buildQuery (
current :
String ,
limit :
Int ):
Seq[String] = {
- Log.info(
"Checking on server side with " +current+
" limit " +limit)
- (1 to limit).map(n => current+
"" +n)
- }
-
def time = Text(timeNow.toString)
-}
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/assets/css/app.css b/combo/example/src/main/webapp/assets/css/app.css
new file mode 100644
index 0000000..a97fb21
--- /dev/null
+++ b/combo/example/src/main/webapp/assets/css/app.css
@@ -0,0 +1,127 @@
+.widget {
+ border:1px solid #ccc;
+ background:#f5f5f5;
+ padding:5px;
+ margin:10px 0 0 0;
+ font-size:8pt;
+}
+
+.sidebar ul {
+ /*margin: 10px 0 0 0;*/
+ padding: 5px;
+}
+
+
+.sidebar ul li {
+ margin:0;
+ padding:0;
+ list-style:none;
+ border:1px solid #ccc;
+ border-bottom:none;
+}
+.sidebar > ul > li:last-child {
+ border-bottom:1px solid #ccc;
+}
+
+.sidebar ul li ul li {
+ margin:0;
+ padding:0;
+ border-style: none;
+ list-style-position: inside;
+ padding-left: 10px;
+
+}
+
+.sidebar ul li ul li a {
+ display: inline;
+}
+
+.sidebar ul li ul {
+ margin: 0;
+ border-bottom: none;
+}
+
+.sidebar ul li ul li span {
+ display:inline;
+ padding:0px;
+}
+
+
+.sidebar ul li a {
+ display:block;
+ padding:3px;
+ text-indent:10px;
+ text-decoration:none;
+}
+
+.sidebar ul li span {
+ display:block;
+ padding:3px;
+ text-indent:10px;
+ text-decoration:none;
+}
+
+
+.sidebar ul li a:hover {
+ background-color: #eee;
+}
+
+
+#poweredBy .alt {
+ color: #666;
+ font-family: "Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua", Georgia, serif;
+ font-style: italic;
+ font-weight: normal;
+}
+
+.lift_error {
+ color: red;
+}
+
+.lift_warning {
+ color: yellow;
+}
+
+.lift_notice {
+}
+
+.main-border {
+ border-left: none;
+}
+
+/*Lift stuff*/
+/*Lift notice*/
+#wrappedNotice #lift__noticesContainer___notice ul,
+#wrappedNotice #lift__noticesContainer___warning ul,
+#wrappedNotice #lift__noticesContainer___error ul
+{
+ padding:5px;
+ list-style-type: none;
+}
+
+#wrappedNotice #lift__noticesContainer___notice {
+ border-radius: 5px;
+ background-color: #D9EDF7;
+ border-color: #BCE8F1;
+ color: #3A87AD;
+}
+
+#wrappedNotice #lift__noticesContainer___warning {
+ border-radius: 5px;
+ background-color: #FCF8E3;
+ border-color: #FBEED5;
+ color: #C09853;
+}
+
+#wrappedNotice #lift__noticesContainer___error {
+ border-radius: 5px;
+ background-color: #F2DEDE;
+ border-color: #EED3D7;
+ color: #B94A48;
+}
+
+@media (min-width: 768px) {
+ .main-border {
+ border-left: 1px solid rgba(0, 0, 0, 0.1);
+ }
+}
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/chat.html b/combo/example/src/main/webapp/chat.html
index 3171029..f654cf3 100644
--- a/combo/example/src/main/webapp/chat.html
+++ b/combo/example/src/main/webapp/chat.html
@@ -1,21 +1,29 @@
-
+
+
+
+
+ Template
+
+
+
+
The total chat app, including the ask/answer component for soliciting a
name
- comments, etc. is listed on this page.
+ comments, etc. is listed on this page.
There is no special code to support AJAX/Comet
(all the wrapping is done automatically by Lift ).
@@ -26,134 +34,99 @@
Until the AskName comet widget provides a name, all rendering messages
are forwarded to AskName.
Here's the code for the "AskName":
-
-
-
-class Chat extends CometActor with CometListener {
- private var userName = ""
- private var chats : List[ChatLine] = Nil
+
+class Chat extends CometActor with CometListener {
+ private var userName = ""
+ private var chats: List[ChatLine] = Nil
-
- private val ulId = S.attr("ul_id" ) openOr "some_ul_id"
+ */
+ private val ulId = S.attr("ul_id") openOr "some_ul_id"
- private val liId = S.attr("li_id" )
+ private val liId = S.attr("li_id")
- private lazy val li = liId.
- flatMap{ Helpers.findId(defaultXml, _) } openOr NodeSeq.Empty
+ private lazy val li = liId.
+ flatMap{ Helpers.findId(defaultHtml, _) } openOr NodeSeq.Empty
- private val inputId = Helpers.nextFuncName
+ private val inputId = Helpers.nextFuncName
- override def lowPriority = {
- case ChatServerUpdate (value ) => {
- val update = (value -- chats).reverse.
- map(b => AppendHtml(ulId, line(b)))
+ // 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 filterNot (chats contains)).reverse.
+ map(b => AppendHtml(ulId, line(b)))
partialUpdate(update)
chats = value
}
}
- override lazy val fixedRender : Box[NodeSeq] =
- S.runTemplate("_chat_fixed" :: Nil,
- "postit" -> Helpers.evalElemWithId {
- (id, elem) =>
- SHtml.onSubmit((s: String) => {
+ // render the input area by binding the
+ // appropriate dynamically generated code to the
+ // view supplied by the template
+ override lazy val fixedRender: Box[NodeSeq] =
+ S.runTemplate("_chat_fixed" :: Nil,
+ "postit" -> Helpers.evalElemWithId {
+ (id, elem) =>
+ SHtml.onSubmit((s: String) => {
ChatServer ! ChatServerMsg(userName, s.trim)
- SetValById(id, "" )
+ SetValById(id, "")
})(elem)
} _)
- private def line (c : ChatLine ) = {
- ("name=when" #> hourFormat(c.when) &
- "name=who" #> c.user &
- "name=body" #> c.msg)(li)
+ // display a line
+ private def line(c: ChatLine) = {
+ ("name=when" #> hourFormat(c.when) &
+ "name=who" #> c.user &
+ "name=body" #> c.msg)(li)
}
- private def displayList : NodeSeq = chats.reverse.flatMap(line)
+ // display a list of chats
+ private def displayList: NodeSeq = chats.reverse.flatMap(line)
- override def render = {
- "name=chat_name" #> userName &
- ("#" +ulId+" *" ) #> displayList
+ // render the whole list of chats
+ override def render = {
+ "name=chat_name" #> userName &
+ ("#"+ulId+" *") #> displayList
}
- override def localSetup {
+ // setup the component
+ override def localSetup {
askForName
- super .localSetup
+ super.localSetup
}
- def registerWith = ChatServer
+ // register as a listener
+ def registerWith = ChatServer
- private def askForName {
- if (userName.length == 0) {
- ask(new AskName, "what's your username" ) {
- case s : String if (s.trim.length > 2) =>
+ // 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 )
+ reRender(true)
- case _ =>
+ case _ =>
askForName
- reRender(false )
+ 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.
-
+
+
+
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/form_ajax.html b/combo/example/src/main/webapp/form_ajax.html
index 40085ab..79d44c1 100644
--- a/combo/example/src/main/webapp/form_ajax.html
+++ b/combo/example/src/main/webapp/form_ajax.html
@@ -1,10 +1,89 @@
-
- Forms with Ajax callback on form element blur
-
- Enter your first and last name:
-
-
+
+
+
+
+
+ Template
+
+
+
+
+
+ Forms with Ajax callback on form element blur
+
+
Enter your first and last name:
+
+
+
+
+ Here's the code:
+
+
+class FormWithAjax extends StatefulSnippet {
+ private var firstName = ""
+ private var lastName = ""
+ private val from = S.referer openOr "/"
+
+ def dispatch = {
+ case _ => render
+ }
+
+ def render = {
+
+ def validate() {
+ (firstName.length, lastName.length) match {
+ case (f, n) if f < 2 && n < 2 =>
+ S.error("First and last names too short")
+ case (f, _) if f < 2 => S.error("First name too short")
+ case (_, n) if n < 2 => S.error("Last name too short")
+ case _ => {
+ S.notice("Ajax form says Thanks!")
+ S.redirectTo(from)
+ }
+ }
+ }
+
+ "#first" #> textAjaxTest(firstName,
+ s => firstName = s,
+ s => {
+ S.notice("First name " + s); Noop
+ },
+ "class" -> "form-control",
+ "type" -> "text",
+ "placeholder" -> "First name") &
+ "#last" #> textAjaxTest(lastName,
+ s => lastName = s,
+ s => {
+ S.notice("Last name " + s); Noop
+ },
+ "class" -> "form-control",
+ "type" -> "text",
+ "placeholder" -> "Last name") &
+ "type=submit" #> submit("Send", validate _)
+ }
+}
+
+
+
+
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/index.html b/combo/example/src/main/webapp/index.html
index 9eb8f2c..630ba38 100644
--- a/combo/example/src/main/webapp/index.html
+++ b/combo/example/src/main/webapp/index.html
@@ -1,54 +1,65 @@
-
- Welcome to the Lift Web Framework
-
-
Lift provides the best features for building interactive
- web applications:
-
-
- Super simple and wicked powerful Ajax and
- Comet coding. This lets you build more interactive, user-friendly
- sites.
-
-
- Amazingly concise code with the powerful type-safety
- of Scala . This means
- more time spent coding features
- and less time writing tests or chasing
- parameter mis-matches.
-
-
- Runs on all standard JEE (Java) application servers
- including Jetty, Tomcat, WebLogic, etc.
- This means you get the performance, scalability and
- compatibility of the best web infrastructure around.
-
-
- Built-in security means more time focusing on your
- application and less time being defensive about
- parameter tampering, SQL injection, Cross Site Scripting and
- other nasty attacks.
-
-
-
-
- Lift is built on Scala , a hybrid Functional and
- O-O language that compiles code down to the Java Virtual Machine.
- Scala code can call any Java code and make use of all Java classes.
- Java code can call some Scala code. Lift applications are packaged as WAR files and
- can be deployed on any
- Servlet 2.4 engine (e.g., Tomcat 5.5.xx, Jetty 6.0, etc.)
-
+
+
+
+
+ Template
+
+
+
-
Lift code is as clean and brief as Rails, yet performs at least 6
- times faster and
- is multithreaded. Additionally, because Scala is strongly typed,
- the compiler
- catches type errors. For example:
+
Welcome to the Lift Web Framework
+
+
Lift provides the best features for building interactive
+ web applications:
+
+
+ Super simple and wicked powerful Ajax and
+ Comet coding. This lets you build more interactive, user-friendly
+ sites.
+
+
+ Amazingly concise code with the powerful type-safety
+ of Scala . This means
+ more time spent coding features
+ and less time writing tests or chasing
+ parameter mis-matches.
+
+
+ Runs on all standard JEE (Java) application servers
+ including Jetty, Tomcat, WebLogic, etc.
+ This means you get the performance, scalability and
+ compatibility of the best web infrastructure around.
+
+
+ Built-in security means more time focusing on your
+ application and less time being defensive about
+ parameter tampering, SQL injection, Cross Site Scripting and
+ other nasty attacks.
+
+
+
+
+
Lift is built on Scala , a hybrid Functional and
+ O-O language that compiles code down to the Java Virtual Machine.
+ Scala code can call any Java code and make use of all Java classes.
+ Java code can call some Scala code. Lift applications are packaged as WAR files and
+ can be deployed on any
+ Servlet 2.4 engine (e.g., Tomcat 5.5.xx, Jetty 6.0, etc.)
+
-
User.find(By(User.email, "foo@bar.com")) // legal
+ Lift code is as clean and brief as Rails, yet performs at least 6
+ times faster and
+ is multithreaded. Additionally, because Scala is strongly typed,
+ the compiler
+ catches type errors. For example:
+
+
User.find(By(User.email, "foo@bar.com")) // legal
User.find(By(User.birthday, new Date("Jan 4, 1975"))) // legal
User.find(By(User.birthday, "foo@bar.com")) // compiler error
-
- Lift is an open source project distributed under an Apache License V2.0
-
+
+
Lift is an open source project distributed under an Apache License V2.0
+
+
+
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/interactive.html b/combo/example/src/main/webapp/interactive.html
index b656645..3f7c817 100644
--- a/combo/example/src/main/webapp/interactive.html
+++ b/combo/example/src/main/webapp/interactive.html
@@ -1,81 +1,56 @@
-
-
- Lift provides powerful facilities to build highly
- interactive web applications.
-
- Ajax
-
- Lift has powerful set of Ajax features that all you to
- create Ajax controls with as little as 1 line of code:
-
-
-
- ajaxButton("", s => {println("you said: "+s); SetHtml("place", <b>{s}</b>)})
-
-
-
-
-
-Comet
-
- Lift supports Comet-style long polling with very little work on the
- part of the developer. Here's the code the implements the clock
- that you see in this demo:
-
-
-
-
-
-
-class Clock extends CometActor {
- override def defaultPrefix = Full("clk" )
- ActorPing.schedule(this , Tick, 10 seconds)
+
+
+
+
+
+ Template
+
+
+
+
+
+ Lift provides powerful facilities to build highly interactive web applications.
+
+
+ Ajax
+ Lift has powerful set of Ajax features that all you to create Ajax controls with as little as 1 line of code:
+ ajaxButton("", s => {println("you said: "+s); SetHtml("place", <b>{s}</b>)})
+
+
+ Comet
+ Lift supports Comet-style long polling with very little work on the part of the developer. Here's the code the implements
+ the clock that you see in this demo:
+
+class ExampleClock(initSession: LiftSession,
+ initType: Box[String],
+ initName: Box[String],
+ initDefaultXml: NodeSeq,
+ initAttributes: Map[String, String])
+ extends CometActor {
+ // schedule a ping every 10 seconds so we redraw
+ Schedule.schedule(this, Tick, 10 seconds)
+
+ def render = "#clock_time *" #> Text(now.toString)
+
+ override def lowPriority = {
+ case Tick =>
+ partialUpdate(SetHtml("clock_time", Text(now.toString)))
+ Schedule.schedule(this, Tick, 10 seconds)
+ }
- private lazy val spanId = uniqueId+"_timespan"
+ val creationInfo = new CometCreationInfo(initType.orNull,
+ initName,
+ initDefaultXml,
+ initAttributes,
+ initSession)
- def render = bind("time" -> timeSpan)
+ initCometActor(creationInfo)
+}
- def timeSpan = (<span id={spanId}>{timeNow}</span>)
+case object Tick
+
+
+
+
- override def lowPriority = {
- case Tick =>
- partialUpdate(SetHtml(spanId, Text(timeNow.toString)))
- ActorPing.schedule(this , Tick, 10 seconds)
- }
-}
-
-
-
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/json.html b/combo/example/src/main/webapp/json.html
index 07540e3..ad3cfbc 100644
--- a/combo/example/src/main/webapp/json.html
+++ b/combo/example/src/main/webapp/json.html
@@ -1,8 +1,17 @@
-
+
+
+
+
+
+ Template
+
+
+
+
JSON Samples
-
+
@@ -12,7 +21,7 @@
Show an error
-
Click Me
+
Click Me
@@ -68,4 +77,7 @@
-
+
+
+
+
diff --git a/combo/example/src/main/webapp/lazy.html b/combo/example/src/main/webapp/lazy.html
index bc3e0e1..ed2585a 100644
--- a/combo/example/src/main/webapp/lazy.html
+++ b/combo/example/src/main/webapp/lazy.html
@@ -1,95 +1,52 @@
-
+
+
+
+
+ Template
+
+
+
Lift supports lazy loading of a snippet. This is
useful when a snippet may take a long time to render,
but you want to return the page to the browser quickly.
-
-
-
+
-
-
+
-
-
+
-
-
+
+
+
The Markup:
+
<div data-lift="lazy-load">
+ <div data-lift="LongTime"></div>
+ </div>
-
-
-
-
-
The Markup:
-
- <div >
- <lift :lazy-load ><div class ="lift:LongTime" ></div ></lift :lazy-load >
- </div >
-
-
-
The Scala Code:
-
-object LongTime {
- def render = {
- val delay = 1000L + randomLong(10000)
+ The Scala Code:
+ object LongTime {
+ def render = {
+ val delay = 1000L + randomLong(10000)
Thread.sleep(delay)
-
+
<div>
This thread delayed {delay / 1000L} seconds
</div>
}
-}
-
+}
-
+
+
diff --git a/combo/example/src/main/webapp/menu/four.html b/combo/example/src/main/webapp/menu/four.html
index 4e65fbc..c4e12dd 100644
--- a/combo/example/src/main/webapp/menu/four.html
+++ b/combo/example/src/main/webapp/menu/four.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 4
diff --git a/combo/example/src/main/webapp/menu/index.html b/combo/example/src/main/webapp/menu/index.html
index 3e7b0e1..d923127 100644
--- a/combo/example/src/main/webapp/menu/index.html
+++ b/combo/example/src/main/webapp/menu/index.html
@@ -1,3 +1,3 @@
-
+
Main Menu page... note the submenus on the menu bar
diff --git a/combo/example/src/main/webapp/menu/one.html b/combo/example/src/main/webapp/menu/one.html
index 39b3634..3b8b1d7 100644
--- a/combo/example/src/main/webapp/menu/one.html
+++ b/combo/example/src/main/webapp/menu/one.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 1
diff --git a/combo/example/src/main/webapp/menu/three.html b/combo/example/src/main/webapp/menu/three.html
index 832bf09..f4d46dd 100644
--- a/combo/example/src/main/webapp/menu/three.html
+++ b/combo/example/src/main/webapp/menu/three.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 3
diff --git a/combo/example/src/main/webapp/menu/two.html b/combo/example/src/main/webapp/menu/two.html
index 560db3e..9bab16b 100644
--- a/combo/example/src/main/webapp/menu/two.html
+++ b/combo/example/src/main/webapp/menu/two.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 2
diff --git a/combo/example/src/main/webapp/menu/two_one.html b/combo/example/src/main/webapp/menu/two_one.html
index 6d2f9e9..0d7c836 100644
--- a/combo/example/src/main/webapp/menu/two_one.html
+++ b/combo/example/src/main/webapp/menu/two_one.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 2-1
diff --git a/combo/example/src/main/webapp/menu/two_two.html b/combo/example/src/main/webapp/menu/two_two.html
index 03cb015..0b8a243 100644
--- a/combo/example/src/main/webapp/menu/two_two.html
+++ b/combo/example/src/main/webapp/menu/two_two.html
@@ -1,3 +1,3 @@
-
+
Submenu Page 2-2
diff --git a/combo/example/src/main/webapp/rhodeisland.html b/combo/example/src/main/webapp/rhodeisland.html
index dc249f3..67b6b39 100644
--- a/combo/example/src/main/webapp/rhodeisland.html
+++ b/combo/example/src/main/webapp/rhodeisland.html
@@ -1,68 +1,48 @@
-
-
-
-
-
- Destroy Rhode Island
-
+
+
- The code:
-
-
-
-
-class JSDialog {
- def button (in : NodeSeq ) =
- ajaxButton(in,
- () => S.runTemplate(List("_jsdialog_confirm" )).
- map(ns => ModalDialog(ns)) openOr
- Alert("Couldn't find _jsdialog_confirm template" ))
+
+
+ Template
+
- def confirm (in : NodeSeq ) =
- bind("confirm" , in,
- "yes" -> ((b: NodeSeq) => ajaxButton(b, () =>
- {println("Rhode Island Destroyed" )
- Unblock & Alert("Rhode Island Destroyed" )})),
- "no" -> ((b: NodeSeq) => <button onclick={Unblock.toJsCmd}>{b}</button>))
-}
-
+
+
+
+
+
+
+ Destroy Rhode Island
+
+
+
The code:
+
+ class JSDialog {
+ // build the button... when pressed, present
+ // a dialog based on running the _jsdialog_confirm
+ // template
+ def button(in: NodeSeq) =
+ ajaxButton(in,
+ () =>
+ S.runTemplate(List("_jsdialog_confirm"))
+ .map(ns => ModalDialog(ns)) openOr
+ Alert("Couldn't find _jsdialog_confirm template"))
+ // the template needs to bind to either server-side behavior
+ // and unblock the UI
+ def confirm = {
+ "#yes" #> ((b: NodeSeq) =>
+ ajaxButton(b, () => {
+ println("Rhode Island Destroyed")
+ Unblock & Alert("Rhode Island Destroyed")
+ })) &
+ "#no" #> ((b: NodeSeq) => <button onclick={Unblock.toJsCmd}>
+ {b}
+ </button>)
+ }
+ }
+
+
+
-
-
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/scripts/jquery.blockUI.js b/combo/example/src/main/webapp/scripts/jquery.blockUI.js
index 342db1a..e708add 100644
--- a/combo/example/src/main/webapp/scripts/jquery.blockUI.js
+++ b/combo/example/src/main/webapp/scripts/jquery.blockUI.js
@@ -1,10 +1,10 @@
-/*
+/*!
* jQuery blockUI plugin
- * Version 2.18 (16-APR-2009)
- * @requires jQuery v1.2.3 or later
+ * Version 2.70.0-2014.11.23
+ * Requires jQuery v1.7 or later
*
* Examples at: http://malsup.com/jquery/block/
- * Copyright (c) 2007-2008 M. Alsup
+ * Copyright (c) 2007-2013 M. Alsup
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
@@ -12,392 +12,609 @@
* Thanks to Amir-Hossein Sobhi for some excellent contributions!
*/
-;(function($) {
-
-if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
- alert('blockUI requires jQuery v1.2.3 or later! You are using v' + $.fn.jquery);
- return;
-}
-
-$.fn._fadeIn = $.fn.fadeIn;
-
-// global $ methods for blocking/unblocking the entire page
-$.blockUI = function(opts) { install(window, opts); };
-$.unblockUI = function(opts) { remove(window, opts); };
-
-// convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
-$.growlUI = function(title, message, timeout) {
- var $m = $('
');
- if (title) $m.append(''+title+' ');
- if (message) $m.append(''+message+' ');
- if (timeout == undefined) timeout = 3000;
- $.blockUI({
- message: $m, fadeIn: 700, fadeOut: 1000, centerY: false,
- timeout: timeout, showOverlay: false,
- css: $.blockUI.defaults.growlCSS
- });
-};
-
-// plugin method for blocking element content
-$.fn.block = function(opts) {
- return this.unblock({ fadeOut: 0 }).each(function() {
- if ($.css(this,'position') == 'static')
- this.style.position = 'relative';
- if ($.browser.msie)
- this.style.zoom = 1; // force 'hasLayout'
- install(this, opts);
- });
-};
-
-// plugin method for unblocking element content
-$.fn.unblock = function(opts) {
- return this.each(function() {
- remove(this, opts);
- });
-};
-
-$.blockUI.version = 2.18; // 2nd generation blocking at no extra cost!
-
-// override these in your code to change the default behavior and style
-$.blockUI.defaults = {
- // message displayed when blocking (use null for no message)
- message: 'Please wait... ',
-
- // styles for the message when blocking; if you wish to disable
- // these and use an external stylesheet then do this in your code:
- // $.blockUI.defaults.css = {};
- css: {
- padding: 0,
- margin: 0,
- width: '30%',
- top: '40%',
- left: '35%',
- textAlign: 'center',
- color: '#000',
- border: '3px solid #aaa',
- backgroundColor:'#fff',
- cursor: 'wait'
- },
-
- // styles for the overlay
- overlayCSS: {
- backgroundColor: '#000',
- opacity: '0.6'
- },
-
- // styles applied when using $.growlUI
- growlCSS: {
- width: '350px',
- top: '10px',
- left: '',
- right: '10px',
- border: 'none',
- padding: '5px',
- opacity: '0.6',
- cursor: null,
- color: '#fff',
- backgroundColor: '#000',
- '-webkit-border-radius': '10px',
- '-moz-border-radius': '10px'
- },
-
- iframeSrc: 'javascript:false', // 'about:blank' fails on HTTPS
-
- // force usage of iframe in non-IE browsers (handy for blocking over objects and applets)
- forceIframe: false,
-
- // z-index for the blocking overlay
- baseZ: 1000,
-
- // set these to true to have the message automatically centered
- centerX: true, // <-- only effects element blocking (page block controlled via css above)
- centerY: true,
-
- // allow body element to be stetched in ie6; this makes blocking look better
- // on "short" pages. disable if you wish to prevent changes to the body height
- allowBodyStretch: true,
-
- // be default blockUI will supress tab navigation from leaving blocking content;
- constrainTabKey: true,
-
- // fadeIn time in millis; set to 0 to disable fadeIn on block
- fadeIn: 200,
-
- // fadeOut time in millis; set to 0 to disable fadeOut on unblock
- fadeOut: 400,
-
- // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
- timeout: 0,
-
- // disable if you don't want to show the overlay
- showOverlay: true,
-
- // if true, focus will be placed in the first available input field when
- // page blocking
- focusInput: true,
-
- // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
- applyPlatformOpacityRules: true,
-
- // callback method invoked when unblocking has completed; the callback is
- // passed the element that has been unblocked (which is the window object for page
- // blocks) and the options that were passed to the unblock call:
- // onUnblock(element, options)
- onUnblock: null,
-
- // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
- quirksmodeOffsetHack: 4
-};
-
-// private data and functions follow...
-
-var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent);
-var pageBlock = null;
-var pageBlockEls = [];
-
-function install(el, opts) {
- var full = (el == window);
- var msg = opts && opts.message !== undefined ? opts.message : undefined;
- opts = $.extend({}, $.blockUI.defaults, opts || {});
- opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
- var css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
- msg = msg === undefined ? opts.message : msg;
-
- // remove the current block (if there is one)
- if (full && pageBlock)
- remove(window, {fadeOut:0});
-
- // if an existing element is being used as the blocking content then we capture
- // its current place in the DOM (and current display style) so we can restore
- // it when we unblock
- if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
- var node = msg.jquery ? msg[0] : msg;
- var data = {};
- $(el).data('blockUI.history', data);
- data.el = node;
- data.parent = node.parentNode;
- data.display = node.style.display;
- data.position = node.style.position;
- if (data.parent)
- data.parent.removeChild(node);
- }
-
- var z = opts.baseZ;
-
- // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
- // layer1 is the iframe layer which is used to supress bleed through of underlying content
- // layer2 is the overlay layer which has opacity and a wait cursor
- // layer3 is the message content that is displayed while blocking
-
- var lyr1 = ($.browser.msie) ? $('')
- : $('
');
- var lyr2 = $('
');
- var lyr3 = full ? $('
')
- : $('
');
-
- // if we have a message, style it
- if (msg)
- lyr3.css(css);
-
- // style the overlay
- if (!opts.applyPlatformOpacityRules || !($.browser.mozilla && /Linux/.test(navigator.platform)))
- lyr2.css(opts.overlayCSS);
- lyr2.css('position', full ? 'fixed' : 'absolute');
-
- // make iframe layer transparent in IE
- if ($.browser.msie)
- lyr1.css('opacity','0.0');
-
- $([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
-
- // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
- var expr = $.browser.msie && ($.browser.version < 8 || !$.boxModel) && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
- if (ie6 || (expr && lyr3[0].style.setExpression)) {
- // give body 100% height
- if (full && opts.allowBodyStretch && $.boxModel)
- $('html,body').css('height','100%');
-
- // fix ie6 issue when blocked element has a border width
- if ((ie6 || !$.boxModel) && !full) {
- var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
- var fixT = t ? '(0 - '+t+')' : 0;
- var fixL = l ? '(0 - '+l+')' : 0;
- }
-
- // simulate fixed position
- $.each([lyr1,lyr2,lyr3], function(i,o) {
- var s = o[0].style;
- s.position = 'absolute';
- if (i < 2) {
- full ? s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"')
- : s.setExpression('height','this.parentNode.offsetHeight + "px"');
- full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
- : s.setExpression('width','this.parentNode.offsetWidth + "px"');
- if (fixL) s.setExpression('left', fixL);
- if (fixT) s.setExpression('top', fixT);
- }
- else if (opts.centerY) {
- if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
- s.marginTop = 0;
- }
- else if (!opts.centerY && full) {
- var top = (opts.css && opts.css.top) ? parseInt(opts.css.top) : 0;
- var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
- s.setExpression('top',expression);
+;(function() {
+/*jshint eqeqeq:false curly:false latedef:false */
+"use strict";
+
+ function setup($) {
+ $.fn._fadeIn = $.fn.fadeIn;
+
+ var noOp = $.noop || function() {};
+
+ // this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
+ // confusing userAgent strings on Vista)
+ var msie = /MSIE/.test(navigator.userAgent);
+ var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
+ var mode = document.documentMode || 0;
+ var setExpr = $.isFunction( document.createElement('div').style.setExpression );
+
+ // global $ methods for blocking/unblocking the entire page
+ $.blockUI = function(opts) { install(window, opts); };
+ $.unblockUI = function(opts) { remove(window, opts); };
+
+ // convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
+ $.growlUI = function(title, message, timeout, onClose) {
+ var $m = $('
');
+ if (title) $m.append(''+title+' ');
+ if (message) $m.append(''+message+' ');
+ if (timeout === undefined) timeout = 3000;
+
+ // Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
+ var callBlock = function(opts) {
+ opts = opts || {};
+
+ $.blockUI({
+ message: $m,
+ fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
+ fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
+ timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
+ centerY: false,
+ showOverlay: false,
+ onUnblock: onClose,
+ css: $.blockUI.defaults.growlCSS
+ });
+ };
+
+ callBlock();
+ var nonmousedOpacity = $m.css('opacity');
+ $m.mouseover(function() {
+ callBlock({
+ fadeIn: 0,
+ timeout: 30000
+ });
+
+ var displayBlock = $('.blockMsg');
+ displayBlock.stop(); // cancel fadeout if it has started
+ displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
+ }).mouseout(function() {
+ $('.blockMsg').fadeOut(1000);
+ });
+ // End konapun additions
+ };
+
+ // plugin method for blocking element content
+ $.fn.block = function(opts) {
+ if ( this[0] === window ) {
+ $.blockUI( opts );
+ return this;
}
- });
- }
-
- // show the message
- if (msg) {
- lyr3.append(msg);
- if (msg.jquery || msg.nodeType)
- $(msg).show();
- }
+ var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
+ this.each(function() {
+ var $el = $(this);
+ if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
+ return;
+ $el.unblock({ fadeOut: 0 });
+ });
+
+ return this.each(function() {
+ if ($.css(this,'position') == 'static') {
+ this.style.position = 'relative';
+ $(this).data('blockUI.static', true);
+ }
+ this.style.zoom = 1; // force 'hasLayout' in ie
+ install(this, opts);
+ });
+ };
+
+ // plugin method for unblocking element content
+ $.fn.unblock = function(opts) {
+ if ( this[0] === window ) {
+ $.unblockUI( opts );
+ return this;
+ }
+ return this.each(function() {
+ remove(this, opts);
+ });
+ };
+
+ $.blockUI.version = 2.70; // 2nd generation blocking at no extra cost!
+
+ // override these in your code to change the default behavior and style
+ $.blockUI.defaults = {
+ // message displayed when blocking (use null for no message)
+ message: 'Please wait... ',
+
+ title: null, // title string; only used when theme == true
+ draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
+
+ theme: false, // set to true to use with jQuery UI themes
+
+ // styles for the message when blocking; if you wish to disable
+ // these and use an external stylesheet then do this in your code:
+ // $.blockUI.defaults.css = {};
+ css: {
+ padding: 0,
+ margin: 0,
+ width: '30%',
+ top: '40%',
+ left: '35%',
+ textAlign: 'center',
+ color: '#000',
+ border: '3px solid #aaa',
+ backgroundColor:'#fff',
+ cursor: 'wait'
+ },
+
+ // minimal style set used when themes are used
+ themedCSS: {
+ width: '30%',
+ top: '40%',
+ left: '35%'
+ },
+
+ // styles for the overlay
+ overlayCSS: {
+ backgroundColor: '#000',
+ opacity: 0.6,
+ cursor: 'wait'
+ },
+
+ // style to replace wait cursor before unblocking to correct issue
+ // of lingering wait cursor
+ cursorReset: 'default',
+
+ // styles applied when using $.growlUI
+ growlCSS: {
+ width: '350px',
+ top: '10px',
+ left: '',
+ right: '10px',
+ border: 'none',
+ padding: '5px',
+ opacity: 0.6,
+ cursor: 'default',
+ color: '#fff',
+ backgroundColor: '#000',
+ '-webkit-border-radius':'10px',
+ '-moz-border-radius': '10px',
+ 'border-radius': '10px'
+ },
+
+ // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
+ // (hat tip to Jorge H. N. de Vasconcelos)
+ /*jshint scripturl:true */
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
+
+ // force usage of iframe in non-IE browsers (handy for blocking applets)
+ forceIframe: false,
+
+ // z-index for the blocking overlay
+ baseZ: 1000,
+
+ // set these to true to have the message automatically centered
+ centerX: true, // <-- only effects element blocking (page block controlled via css above)
+ centerY: true,
+
+ // allow body element to be stetched in ie6; this makes blocking look better
+ // on "short" pages. disable if you wish to prevent changes to the body height
+ allowBodyStretch: true,
+
+ // enable if you want key and mouse events to be disabled for content that is blocked
+ bindEvents: true,
+
+ // be default blockUI will supress tab navigation from leaving blocking content
+ // (if bindEvents is true)
+ constrainTabKey: true,
+
+ // fadeIn time in millis; set to 0 to disable fadeIn on block
+ fadeIn: 200,
+
+ // fadeOut time in millis; set to 0 to disable fadeOut on unblock
+ fadeOut: 400,
+
+ // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
+ timeout: 0,
+
+ // disable if you don't want to show the overlay
+ showOverlay: true,
+
+ // if true, focus will be placed in the first available input field when
+ // page blocking
+ focusInput: true,
+
+ // elements that can receive focus
+ focusableElements: ':input:enabled:visible',
+
+ // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
+ // no longer needed in 2012
+ // applyPlatformOpacityRules: true,
+
+ // callback method invoked when fadeIn has completed and blocking message is visible
+ onBlock: null,
+
+ // callback method invoked when unblocking has completed; the callback is
+ // passed the element that has been unblocked (which is the window object for page
+ // blocks) and the options that were passed to the unblock call:
+ // onUnblock(element, options)
+ onUnblock: null,
+
+ // callback method invoked when the overlay area is clicked.
+ // setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
+ onOverlayClick: null,
+
+ // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
+ quirksmodeOffsetHack: 4,
+
+ // class name of the message block
+ blockMsgClass: 'blockMsg',
+
+ // if it is already blocked, then ignore it (don't unblock and reblock)
+ ignoreIfBlocked: false
+ };
+
+ // private data and functions follow...
+
+ var pageBlock = null;
+ var pageBlockEls = [];
+
+ function install(el, opts) {
+ var css, themedCSS;
+ var full = (el == window);
+ var msg = (opts && opts.message !== undefined ? opts.message : undefined);
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
+
+ if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
+ return;
+
+ opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
+ css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
+ if (opts.onOverlayClick)
+ opts.overlayCSS.cursor = 'pointer';
+
+ themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
+ msg = msg === undefined ? opts.message : msg;
+
+ // remove the current block (if there is one)
+ if (full && pageBlock)
+ remove(window, {fadeOut:0});
- if ($.browser.msie && opts.showOverlay)
- lyr1.show(); // opacity is zero
- if (opts.fadeIn) {
- if (opts.showOverlay)
- lyr2._fadeIn(opts.fadeIn);
- if (msg)
- lyr3.fadeIn(opts.fadeIn);
- }
- else {
- if (opts.showOverlay)
- lyr2.show();
- if (msg)
- lyr3.show();
- }
+ // if an existing element is being used as the blocking content then we capture
+ // its current place in the DOM (and current display style) so we can restore
+ // it when we unblock
+ if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
+ var node = msg.jquery ? msg[0] : msg;
+ var data = {};
+ $(el).data('blockUI.history', data);
+ data.el = node;
+ data.parent = node.parentNode;
+ data.display = node.style.display;
+ data.position = node.style.position;
+ if (data.parent)
+ data.parent.removeChild(node);
+ }
+
+ $(el).data('blockUI.onUnblock', opts.onUnblock);
+ var z = opts.baseZ;
+
+ // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
+ // layer1 is the iframe layer which is used to supress bleed through of underlying content
+ // layer2 is the overlay layer which has opacity and a wait cursor (by default)
+ // layer3 is the message content that is displayed while blocking
+ var lyr1, lyr2, lyr3, s;
+ if (msie || opts.forceIframe)
+ lyr1 = $('');
+ else
+ lyr1 = $('
');
+
+ if (opts.theme)
+ lyr2 = $('
');
+ else
+ lyr2 = $('
');
+
+ if (opts.theme && full) {
+ s = '';
+ if ( opts.title ) {
+ s += '';
+ }
+ s += '
';
+ s += '
';
+ }
+ else if (opts.theme) {
+ s = '';
+ }
+ else if (full) {
+ s = '
';
+ }
+ else {
+ s = '
';
+ }
+ lyr3 = $(s);
+
+ // if we have a message, style it
+ if (msg) {
+ if (opts.theme) {
+ lyr3.css(themedCSS);
+ lyr3.addClass('ui-widget-content');
+ }
+ else
+ lyr3.css(css);
+ }
+
+ // style the overlay
+ if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
+ lyr2.css(opts.overlayCSS);
+ lyr2.css('position', full ? 'fixed' : 'absolute');
+
+ // make iframe layer transparent in IE
+ if (msie || opts.forceIframe)
+ lyr1.css('opacity',0.0);
+
+ //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
+ var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
+ $.each(layers, function() {
+ this.appendTo($par);
+ });
+
+ if (opts.theme && opts.draggable && $.fn.draggable) {
+ lyr3.draggable({
+ handle: '.ui-dialog-titlebar',
+ cancel: 'li'
+ });
+ }
+
+ // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
+ var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);
+ if (ie6 || expr) {
+ // give body 100% height
+ if (full && opts.allowBodyStretch && $.support.boxModel)
+ $('html,body').css('height','100%');
+
+ // fix ie6 issue when blocked element has a border width
+ if ((ie6 || !$.support.boxModel) && !full) {
+ var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
+ var fixT = t ? '(0 - '+t+')' : 0;
+ var fixL = l ? '(0 - '+l+')' : 0;
+ }
+
+ // simulate fixed position
+ $.each(layers, function(i,o) {
+ var s = o[0].style;
+ s.position = 'absolute';
+ if (i < 2) {
+ if (full)
+ s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"');
+ else
+ s.setExpression('height','this.parentNode.offsetHeight + "px"');
+ if (full)
+ s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"');
+ else
+ s.setExpression('width','this.parentNode.offsetWidth + "px"');
+ if (fixL) s.setExpression('left', fixL);
+ if (fixT) s.setExpression('top', fixT);
+ }
+ else if (opts.centerY) {
+ if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
+ s.marginTop = 0;
+ }
+ else if (!opts.centerY && full) {
+ var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
+ var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
+ s.setExpression('top',expression);
+ }
+ });
+ }
+
+ // show the message
+ if (msg) {
+ if (opts.theme)
+ lyr3.find('.ui-widget-content').append(msg);
+ else
+ lyr3.append(msg);
+ if (msg.jquery || msg.nodeType)
+ $(msg).show();
+ }
+
+ if ((msie || opts.forceIframe) && opts.showOverlay)
+ lyr1.show(); // opacity is zero
+ if (opts.fadeIn) {
+ var cb = opts.onBlock ? opts.onBlock : noOp;
+ var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
+ var cb2 = msg ? cb : noOp;
+ if (opts.showOverlay)
+ lyr2._fadeIn(opts.fadeIn, cb1);
+ if (msg)
+ lyr3._fadeIn(opts.fadeIn, cb2);
+ }
+ else {
+ if (opts.showOverlay)
+ lyr2.show();
+ if (msg)
+ lyr3.show();
+ if (opts.onBlock)
+ opts.onBlock.bind(lyr3)();
+ }
+
+ // bind key and mouse events
+ bind(1, el, opts);
+
+ if (full) {
+ pageBlock = lyr3[0];
+ pageBlockEls = $(opts.focusableElements,pageBlock);
+ if (opts.focusInput)
+ setTimeout(focus, 20);
+ }
+ else
+ center(lyr3[0], opts.centerX, opts.centerY);
+
+ if (opts.timeout) {
+ // auto-unblock
+ var to = setTimeout(function() {
+ if (full)
+ $.unblockUI(opts);
+ else
+ $(el).unblock(opts);
+ }, opts.timeout);
+ $(el).data('blockUI.timeout', to);
+ }
+ }
+
+ // remove the block
+ function remove(el, opts) {
+ var count;
+ var full = (el == window);
+ var $el = $(el);
+ var data = $el.data('blockUI.history');
+ var to = $el.data('blockUI.timeout');
+ if (to) {
+ clearTimeout(to);
+ $el.removeData('blockUI.timeout');
+ }
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
+ bind(0, el, opts); // unbind events
+
+ if (opts.onUnblock === null) {
+ opts.onUnblock = $el.data('blockUI.onUnblock');
+ $el.removeData('blockUI.onUnblock');
+ }
+
+ var els;
+ if (full) // crazy selector to handle odd field errors in ie6/7
+ els = $('body').children().filter('.blockUI').add('body > .blockUI');
+ else
+ els = $el.find('>.blockUI');
+
+ // fix cursor issue
+ if ( opts.cursorReset ) {
+ if ( els.length > 1 )
+ els[1].style.cursor = opts.cursorReset;
+ if ( els.length > 2 )
+ els[2].style.cursor = opts.cursorReset;
+ }
+
+ if (full)
+ pageBlock = pageBlockEls = null;
+
+ if (opts.fadeOut) {
+ count = els.length;
+ els.stop().fadeOut(opts.fadeOut, function() {
+ if ( --count === 0)
+ reset(els,data,opts,el);
+ });
+ }
+ else
+ reset(els, data, opts, el);
+ }
+
+ // move blocking element back into the DOM where it started
+ function reset(els,data,opts,el) {
+ var $el = $(el);
+ if ( $el.data('blockUI.isBlocked') )
+ return;
+
+ els.each(function(i,o) {
+ // remove via DOM calls so we don't lose event handlers
+ if (this.parentNode)
+ this.parentNode.removeChild(this);
+ });
+
+ if (data && data.el) {
+ data.el.style.display = data.display;
+ data.el.style.position = data.position;
+ data.el.style.cursor = 'default'; // #59
+ if (data.parent)
+ data.parent.appendChild(data.el);
+ $el.removeData('blockUI.history');
+ }
+
+ if ($el.data('blockUI.static')) {
+ $el.css('position', 'static'); // #22
+ }
+
+ if (typeof opts.onUnblock == 'function')
+ opts.onUnblock(el,opts);
+
+ // fix issue in Safari 6 where block artifacts remain until reflow
+ var body = $(document.body), w = body.width(), cssW = body[0].style.width;
+ body.width(w-1).width(w);
+ body[0].style.width = cssW;
+ }
+
+ // bind/unbind the handler
+ function bind(b, el, opts) {
+ var full = el == window, $el = $(el);
+
+ // don't bother unbinding if there is nothing to unbind
+ if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
+ return;
+
+ $el.data('blockUI.isBlocked', b);
+
+ // don't bind events when overlay is not in use or if bindEvents is false
+ if (!full || !opts.bindEvents || (b && !opts.showOverlay))
+ return;
+
+ // bind anchors and inputs for mouse and key events
+ var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
+ if (b)
+ $(document).bind(events, opts, handler);
+ else
+ $(document).unbind(events, handler);
+
+ // former impl...
+ // var $e = $('a,:input');
+ // b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
+ }
+
+ // event handler to suppress keyboard/mouse events when blocking
+ function handler(e) {
+ // allow tab navigation (conditionally)
+ if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
+ if (pageBlock && e.data.constrainTabKey) {
+ var els = pageBlockEls;
+ var fwd = !e.shiftKey && e.target === els[els.length-1];
+ var back = e.shiftKey && e.target === els[0];
+ if (fwd || back) {
+ setTimeout(function(){focus(back);},10);
+ return false;
+ }
+ }
+ }
+ var opts = e.data;
+ var target = $(e.target);
+ if (target.hasClass('blockOverlay') && opts.onOverlayClick)
+ opts.onOverlayClick(e);
+
+ // allow events within the message content
+ if (target.parents('div.' + opts.blockMsgClass).length > 0)
+ return true;
+
+ // allow events for content that is not being blocked
+ return target.parents().children().filter('div.blockUI').length === 0;
+ }
+
+ function focus(back) {
+ if (!pageBlockEls)
+ return;
+ var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
+ if (e)
+ e.focus();
+ }
+
+ function center(el, x, y) {
+ var p = el.parentNode, s = el.style;
+ var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
+ var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
+ if (x) s.left = l > 0 ? (l+'px') : '0';
+ if (y) s.top = t > 0 ? (t+'px') : '0';
+ }
+
+ function sz(el, p) {
+ return parseInt($.css(el,p),10)||0;
+ }
- // bind key and mouse events
- bind(1, el, opts);
-
- if (full) {
- pageBlock = lyr3[0];
- pageBlockEls = $(':input:enabled:visible',pageBlock);
- if (opts.focusInput)
- setTimeout(focus, 20);
- }
- else
- center(lyr3[0], opts.centerX, opts.centerY);
-
- if (opts.timeout) {
- // auto-unblock
- var to = setTimeout(function() {
- full ? $.unblockUI(opts) : $(el).unblock(opts);
- }, opts.timeout);
- $(el).data('blockUI.timeout', to);
}
-};
-
-// remove the block
-function remove(el, opts) {
- var full = el == window;
- var $el = $(el);
- var data = $el.data('blockUI.history');
- var to = $el.data('blockUI.timeout');
- if (to) {
- clearTimeout(to);
- $el.removeData('blockUI.timeout');
+
+
+ /*global define:true */
+ if (typeof define === 'function' && define.amd && define.amd.jQuery) {
+ define(['jquery'], setup);
+ } else {
+ setup(jQuery);
}
- opts = $.extend({}, $.blockUI.defaults, opts || {});
- bind(0, el, opts); // unbind events
- var els = full ? $('body').children().filter('.blockUI') : $('.blockUI', el);
-
- if (full)
- pageBlock = pageBlockEls = null;
-
- if (opts.fadeOut) {
- els.fadeOut(opts.fadeOut);
- setTimeout(function() { reset(els,data,opts,el); }, opts.fadeOut);
- }
- else
- reset(els, data, opts, el);
-};
-
-// move blocking element back into the DOM where it started
-function reset(els,data,opts,el) {
- els.each(function(i,o) {
- // remove via DOM calls so we don't lose event handlers
- if (this.parentNode)
- this.parentNode.removeChild(this);
- });
-
- if (data && data.el) {
- data.el.style.display = data.display;
- data.el.style.position = data.position;
- if (data.parent)
- data.parent.appendChild(data.el);
- $(data.el).removeData('blockUI.history');
- }
-
- if (typeof opts.onUnblock == 'function')
- opts.onUnblock(el,opts);
-};
-
-// bind/unbind the handler
-function bind(b, el, opts) {
- var full = el == window, $el = $(el);
-
- // don't bother unbinding if there is nothing to unbind
- if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
- return;
- if (!full)
- $el.data('blockUI.isBlocked', b);
-
- if (b && !opts.showOverlay) // don't prevent events when overlay not in use
- return;
-
- // bind anchors and inputs for mouse and key events
- var events = 'mousedown mouseup keydown keypress';
- b ? $(document).bind(events, opts, handler) : $(document).unbind(events, handler);
-
-// former impl...
-// var $e = $('a,:input');
-// b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
-};
-
-// event handler to suppress keyboard/mouse events when blocking
-function handler(e) {
- // allow tab navigation (conditionally)
- if (e.keyCode && e.keyCode == 9) {
- if (pageBlock && e.data.constrainTabKey) {
- var els = pageBlockEls;
- var fwd = !e.shiftKey && e.target == els[els.length-1];
- var back = e.shiftKey && e.target == els[0];
- if (fwd || back) {
- setTimeout(function(){focus(back)},10);
- return false;
- }
- }
- }
- // allow events within the message content
- if ($(e.target).parents('div.blockMsg').length > 0)
- return true;
-
- // allow events for content that is not being blocked
- return $(e.target).parents().children().filter('div.blockUI').length == 0;
-};
-
-function focus(back) {
- if (!pageBlockEls)
- return;
- var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
- if (e)
- e.focus();
-};
-
-function center(el, x, y) {
- var p = el.parentNode, s = el.style;
- var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
- var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
- if (x) s.left = l > 0 ? (l+'px') : '0';
- if (y) s.top = t > 0 ? (t+'px') : '0';
-};
-
-function sz(el, p) {
- return parseInt($.css(el,p))||0;
-};
-
-})(jQuery);
+
+})();
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/stateless_json.html b/combo/example/src/main/webapp/stateless_json.html
index 14fed56..8c565a9 100644
--- a/combo/example/src/main/webapp/stateless_json.html
+++ b/combo/example/src/main/webapp/stateless_json.html
@@ -1,81 +1,66 @@
-
- Stateless JSON Sample
-
+
+
+
+
+
+ Template
+
+
+
+
+
+
+ Stateless JSON Sample
+
+
-
+
Show
Show in Textile
Count Characters
Show an error
-
+
Click Me
-
Here's the code:
-
+
Here's the code:
-
-
-
-
-object StatelessJson {
- def init () {
- LiftRules.statelessDispatchTable.append {
- case r @ Req ("stateless_json_call" :: Nil , _ , PostRequest ) => () => handleJson(r)
+
+object StatelessJson {
+ def init() {
+ // register the JSON handler
+ LiftRules.statelessDispatch.append {
+ case r @ Req("stateless_json_call" :: Nil, _, PostRequest) =>
+ () =>
+ handleJson(r)
}
}
- implicit def iterableToBox [X ](in : Iterable[X] ): Box[X] = in.toList.headOption
+ implicit def iterableToBox[X](in: Iterable[X]): Box[X] =
+ in.toList.headOption
- def handleJson (req : Req ): Box[LiftResponse] =
- for {
- json <- req.json JObject(List(JField("command" , JString(cmd)), JField("params" , JString(params)))) <- json } yield JavaScriptResponse(SetHtml("json_result" ,cmd match { case "show" => Text(params)
- case "textile" => TextileParser.toHtml(params, Empty)
- case "count" => Text(params.length+" Characters" )
- case x => <b>Problem... didn't handle JSON message {x}</b>
- }))
+ def handleJson(req: Req): Box[LiftResponse] =
+ for {
+ json <- req.json // get the JSON
+ JObject(
+ List(JField("command", JString(cmd)),
+ JField("params", JString(params)))) <- json // extract the command
+ } yield
+ JavaScriptResponse(
+ SetHtml(
+ "json_result",
+ cmd match { // build the response
+ case "show" => Text(params)
+ case "textile" => TextileParser.toHtml(params, Empty)
+ case "count" => Text(params.length + " Characters")
+ case x => <b>Problem... didn't handle JSON message {x}</b>
+ }
+ ))
}
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/templates-hidden/default.html b/combo/example/src/main/webapp/templates-hidden/default.html
index 9efdede..b62c7c2 100644
--- a/combo/example/src/main/webapp/templates-hidden/default.html
+++ b/combo/example/src/main/webapp/templates-hidden/default.html
@@ -6,10 +6,18 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+ * The singleton that has methods for accessing the database
+ */
+object User extends User with KeyedMetaMapper[Long, User] {
+ override def dbTableName = "users" // define the DB table name
-
-
-object User extends User with KeyedMetaMapper [Long , User ] {
- override def dbTableName = "users"
- override lazy val fieldOrder = List(id, firstName, lastName,
- email, password, textArea)
+ // define the order fields will appear in forms and output
+ override lazy val fieldOrder =
+ List(id, firstName, lastName, email, password, textArea)
}
-
-class User extends ProtoUser [User ] {
- def getSingleton = User
-
- object textArea extends MappedTextarea (this , 2048) {
- override def textareaRows = 10
- override def textareaCols = 50
- override def displayName = "Personal Essay"
+/**
+ * An O-R mapped "User" class that includes first name, last name,
+ * password and we add a "Personal Essay" to it
+ */
+class User extends ProtoUser[User] {
+ def getSingleton = User
+
+ // define an additional field for a personal essay
+ object textArea extends MappedTextarea(this, 2048) {
+ override def textareaRows = 10
+ override def textareaCols = 50
+ override def displayName = "Personal Essay"
}
}
-
+
For this little bit of work, we get a complete user with
first name, last name, password, email, and a personal essay.
@@ -80,4 +56,7 @@
how to convert itself to a string, to XML, and even generate
HTML forms for itself.
-
+
+
+
+
diff --git a/combo/example/src/main/webapp/json.html b/combo/example/src/main/webapp/json.html
index ad3cfbc..ee06767 100644
--- a/combo/example/src/main/webapp/json.html
+++ b/combo/example/src/main/webapp/json.html
@@ -2,49 +2,87 @@
-
-
Template
+
+
Template
-
-
JSON Samples
-
-
+
+
+ JSON Samples
+
+
+
+
Enter an addition question:
+
+
+
+
+
+
+
+
+
-
-
-
- Show
- Show in Textile
- Count Characters
- Show an error
-
-
-
Click Me
-
-
+
+
+
+
+
+ Show
+ Show in Textile
+ Count Characters
+ Show an error
+
+
+
Click Me
+
+
-
Here's the code:
+
Here's the code:
+
+/**
+ * The singleton that has methods for accessing the database
+ */
+object User extends User with KeyedMetaMapper[Long, User] {
+ override def dbTableName = "users" // define the DB table name
-
-
-object User extends User with KeyedMetaMapper [Long , User ] {
- override def dbTableName = "users"
- override lazy val fieldOrder = List(id, firstName, lastName,
- email, password, textArea)
+ // define the order fields will appear in forms and output
+ override lazy val fieldOrder =
+ List(id, firstName, lastName, email, password, textArea)
}
-
-class User extends ProtoUser [User ] {
- def getSingleton = User
-
- object textArea extends MappedTextarea (this , 2048) {
- override def textareaRows = 10
- override def textareaCols = 50
- override def displayName = "Personal Essay"
+/**
+ * An O-R mapped "User" class that includes first name, last name,
+ * password and we add a "Personal Essay" to it
+ */
+class User extends ProtoUser[User] {
+ def getSingleton = User
+
+ // define an additional field for a personal essay
+ object textArea extends MappedTextarea(this, 2048) {
+ override def textareaRows = 10
+ override def textareaCols = 50
+ override def displayName = "Personal Essay"
}
}
-
+
For this little bit of work, we get a complete user with
first name, last name, password, email, and a personal essay.
@@ -80,4 +56,7 @@
how to convert itself to a string, to XML, and even generate
HTML forms for itself.
-
+
+
+
+
diff --git a/combo/example/src/main/webapp/json.html b/combo/example/src/main/webapp/json.html
index ad3cfbc..ee06767 100644
--- a/combo/example/src/main/webapp/json.html
+++ b/combo/example/src/main/webapp/json.html
@@ -2,49 +2,87 @@
-
-
Template
+
+
Template
-
-
JSON Samples
-
-
+
+
+ JSON Samples
+
+
+
+
Enter an addition question:
+
+
+
+
+
+
+
+
+
-
-
-
- Show
- Show in Textile
- Count Characters
- Show an error
-
-
-
Click Me
-
-
+
+
+
+
+
+ Show
+ Show in Textile
+ Count Characters
+ Show an error
+
+
+
Click Me
+
+
-
Here's the code:
+
Here's the code:
diff --git a/combo/example/src/main/webapp/json_more.html b/combo/example/src/main/webapp/json_more.html
index 13c39cc..2bdea50 100644
--- a/combo/example/src/main/webapp/json_more.html
+++ b/combo/example/src/main/webapp/json_more.html
@@ -1,11 +1,28 @@
-
- More JSON Samples
-
-
-
-
-
- This example calls the
noParam
function which
- invokes a server-side JSON call that then calls a handler
- back in the browser.
-
Press Me
-
-
- The client-side JavaScript for looks like:
-
+ // ]]>
+
+ This example calls the
+ noParam
function which invokes a server-side JSON call that then calls a handler back in the browser.
+ Press Me
+
+ The client-side JavaScript for looks like:
+
<script >
// <![CDATA[
function callNoParam() {
@@ -35,13 +50,13 @@
// ]]>
</script >
-
+
+
+
-
-
-
-
+ // ]]>
+
- Let's send the contents of a test field and process it:
+ Let's send the contents of a test field and process it:
-
-
Press Me
-
-
-
- The Script to do this is:
-
+
+ Press Me
+
+
+ The Script to do this is:
+
<script >
// <![CDATA[
function stringSender() {
@@ -78,13 +92,13 @@
</script >
-
+
-
-
-
-
-
-
- Let's send some numbers to the server and have the server
- add 1 to each of the numbers.
-
- Enter comma separated numbers:
-
- Click Me
-
-
-
-
-
-
+
+
+
+
+
+ The server-side code looks like:
+
+
new JsonHandler {
def apply (in : Any ): JsCmd = in match {
case JsonCmd ("noParam" , resp , _ , _ ) =>
@@ -157,6 +174,9 @@
+
+
+
-
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/persistence.html b/combo/example/src/main/webapp/persistence.html
index 70827cf..7f03848 100644
--- a/combo/example/src/main/webapp/persistence.html
+++ b/combo/example/src/main/webapp/persistence.html
@@ -10,6 +10,14 @@
Persistence
+
+
+
+ Home
+
+ Persistence
+
+
Lift comes with its own ActiveRecord-like OR mapper called mapper. It's great for small projects. Lift also supports
JPA .
diff --git a/combo/example/src/main/webapp/rhodeisland.html b/combo/example/src/main/webapp/rhodeisland.html
index 67b6b39..599fe75 100644
--- a/combo/example/src/main/webapp/rhodeisland.html
+++ b/combo/example/src/main/webapp/rhodeisland.html
@@ -11,6 +11,24 @@
+
Modal Dialog
+
+
+
+ Home
+
+
+ Interactive Stuff
+
+ Modal Dialog
+
+
+
+
This section has two examples showing how you could work with modal dialogs that has there template data in a separate
+ file. The first example is a plain javascript dialog while the other one is taking advantage of bootstrap's javascript
+ modals.
+
+
JS dialog example
Destroy Rhode Island
@@ -42,6 +60,59 @@
}
}
+
+
Bootstrap dialog example
+
Destroy Rhode Island
+
+
+
The code:
+
+class BSDialog {
+ // build the button... when pressed, present
+ // a dialog based on the _bsdialog_confirm
+ // template
+ def button(in: NodeSeq) =
+ ajaxButton(in,
+ () => injectDialogTemplate & openDialog,
+ "type" -> "button",
+ "class" -> "btn btn-primary",
+ "data-target" -> "#exampleModal")
+
+ def confirm = {
+ "#yes" #> ((b: NodeSeq) =>
+ ajaxButton(b, () => {
+ logger.debug("Rhode Island Destroyed")
+ showDestroyAlert & closeDialog
+ }, "type" -> "button", "class" -> "btn btn-primary")) &
+ "#no" #> ((b: NodeSeq) =>
+ ajaxButton(
+ b,
+ () => {
+ logger.debug("Rhode Island intact")
+ Noop //we could have used closeDialog here but we are instead using the data-dismiss attribute.
+ },
+ "type" -> "button",
+ "class" -> "btn btn-primary",
+ "data-dismiss" -> "modal"
+ ))
+ }
+
+ private val logger = Logger(classOf[BSDialog])
+ private val bsDialogTemplate: Box[NodeSeq] = Templates(
+ List("_bsdialog_confirm"))
+ private val openDialog
+ : JsCmd = JsRaw("""$('#exampleModal').modal('show')""").cmd
+ private val closeDialog
+ : JsCmd = JsRaw("""$('#exampleModal').modal('hide')""").cmd
+ private val showDestroyAlert = Alert("Rhode Island Destroyed")
+ private val showTemplateNotFoundAlert = Alert(
+ "Couldn't find _bsdialog_confirm template")
+
+ private def setAtPlaceholder(ns: NodeSeq) = SetHtml("modalPlaceholder", ns)
+ private def injectDialogTemplate =
+ bsDialogTemplate map setAtPlaceholder openOr showTemplateNotFoundAlert
+}
+
diff --git a/combo/example/src/main/webapp/simple/add.html b/combo/example/src/main/webapp/simple/add.html
index b980d97..3c80cc9 100644
--- a/combo/example/src/main/webapp/simple/add.html
+++ b/combo/example/src/main/webapp/simple/add.html
@@ -8,12 +8,30 @@
+
Add User
+
+
+
+ Home
+
+
+ Persistence
+
+
+ Simple Forms
+
+ Add User
+
+
+
-
+
diff --git a/combo/example/src/main/webapp/simple/delete.html b/combo/example/src/main/webapp/simple/delete.html
index 64a6ecf..b2a6d68 100644
--- a/combo/example/src/main/webapp/simple/delete.html
+++ b/combo/example/src/main/webapp/simple/delete.html
@@ -8,11 +8,24 @@
+
Delete User
+
+
+
+ Home
+
+
+ Persistence
+
+
+ Simple Forms
+
+ Delete User
+
+
diff --git a/combo/example/src/main/webapp/simple/edit.html b/combo/example/src/main/webapp/simple/edit.html
index 89b947a..6a29e6b 100644
--- a/combo/example/src/main/webapp/simple/edit.html
+++ b/combo/example/src/main/webapp/simple/edit.html
@@ -8,6 +8,24 @@
+
Edit User
+
+
+
+ Home
+
+
+ Persistence
+
+
+ Simple Forms
+
+ Edit User
+
+
+
foo
diff --git a/combo/example/src/main/webapp/simple/index.html b/combo/example/src/main/webapp/simple/index.html
index 050208d..d1b6c8e 100644
--- a/combo/example/src/main/webapp/simple/index.html
+++ b/combo/example/src/main/webapp/simple/index.html
@@ -5,15 +5,27 @@
Template
-
-
Add a User
+
Simple Forms
+
+
+
+ Home
+
+
+ Persistence
+
+ Simple Forms
+
+
+
+
Add a User
diff --git a/combo/example/src/main/webapp/stateless_json.html b/combo/example/src/main/webapp/stateless_json.html
index 31a48d0..679afd7 100644
--- a/combo/example/src/main/webapp/stateless_json.html
+++ b/combo/example/src/main/webapp/stateless_json.html
@@ -9,9 +9,20 @@
-
- Stateless JSON Sample
-
+
+
Stateless JSON Sample
+
+
+
+ Home
+
+
+ Interactive Stuff
+
+ Stateless JSON Sample
+
+
+
@@ -26,9 +37,7 @@
Click Me
-
-
Here's the code:
-
+
Here's the code:
object StatelessJson {
def init() {
diff --git a/combo/example/src/main/webapp/templates-hidden/default2.html b/combo/example/src/main/webapp/templates-hidden/default2.html
index bd77988..8401a43 100644
--- a/combo/example/src/main/webapp/templates-hidden/default2.html
+++ b/combo/example/src/main/webapp/templates-hidden/default2.html
@@ -1,4 +1,4 @@
-
+
diff --git a/combo/example/src/main/webapp/templating/embed.html b/combo/example/src/main/webapp/templating/embed.html
index 3a39119..7b1638c 100644
--- a/combo/example/src/main/webapp/templating/embed.html
+++ b/combo/example/src/main/webapp/templating/embed.html
@@ -1,119 +1,63 @@
-
-
- Lift Example
-
-
-
-
-
-
- In addition surrounding XHTML with a template, you
- can also embed a template at the current point in
- the page rendering with the <lift:embed/> tag.
-
-
-
-
-
- The above paragraph was embedded using this code:
-
-
-
-
-
- <lift :embed what ="/templating/_sample_embed" />
-
-
-
- Templates that start with the underscore ('_') or period ('.')
- characters will not be served directly by Lift, but may be
- accessed using the surround and embed tags.
-
-
-
- Lift will select templates based on the current localization
- setting for the session. Lift uses the function in
- LiftRules.localeCalculator
to determine the
- current locale for template selection. By default the
- function is:
-
-
- def defaultLocaleCalculator (request : Box[HttpServletRequest] ) =
- request.flatMap(_.getLocale() match
- {case null => Empty
- case l : Locale => Full (l )}).openOr(Locale.getDefault())
-
-
-But you can customize the function to return the locale of
-the currently logged in user, detect the IP address of the request,
-etc.
-
-
-
- Based on the locale, Lift will look for templates based on
- the base template name, in this case
- '/templating/_sample_embed'
and
- then append an underscore ('_') followed by the complete locale, for
- example 'en_US'. So, Lift will look for
- '/templating/_sample_embed_en_US.html'
. If that resource
- is not available, Lift will look for
- '/templating/_sample_embed_en.html'
and finally
- '/templating/_sample_embed.html'
.
-
-
-
-
+
+
+
+
+
+ Template
+
+
+
+
+
Embed
+
+
+
+ Home
+
+
+ Templating
+
+ Embed
+
+
+
+ In addition surrounding HTML with a template, you can also embed a template at the current point in the page rendering a
+ tag with the
+ data-lift='embed?what=...'
attribute.
+
+
+
+
+
+ The above paragraph was embedded using this code:
+
+
<span data-lift="embed?what=/templating/_sample_embed"></span>
+
+
+ Templates that start with the underscore ('_') or period ('.') characters will not be served directly by Lift, but may be
+ accessed using the surround and embed tags.
+
+
+
+ Lift will select templates based on the current localization setting for the session. Lift uses the function in
+ LiftRules.localeCalculator
to determine the current locale for template selection. By default the function is:
+
+
def defaultLocaleCalculator(request: Box[HttpServletRequest]) =
+ request.flatMap(_.getLocale() match
+ {case null => Empty
+ case l: Locale => Full(l)}).openOr(Locale.getDefault())
But you can customize the function to return the locale of the currently logged in user, detect the IP address of
+ the request, etc.
+
+
+
+ Based on the locale, Lift will look for templates based on the base template name, in this case
+ '/templating/_sample_embed'
and then append an underscore ('_') followed by the complete locale, for example
+ 'en_US'. So, Lift will look for
+ '/templating/_sample_embed_en_US.html'
. If that resource is not available, Lift will look for
+ '/templating/_sample_embed_en.html'
and finally
+ '/templating/_sample_embed.html'
.
+
+
+
+
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/templating/index.html b/combo/example/src/main/webapp/templating/index.html
index 693fb0b..73d7792 100644
--- a/combo/example/src/main/webapp/templating/index.html
+++ b/combo/example/src/main/webapp/templating/index.html
@@ -1,65 +1,118 @@
-
-
+ The following is David Pollak's take on web framework view technology:
+
+
The Lift design is born out of my experience (both good and bad) with a variety of technologies including Rails.
+
+
I think the best paper on the subject is Terrence Parr's work on
+
+ StringTemplate .
+
+
My first design goal with Lift was to make sure that no programming logic and no programming symbols make it into the
+ static display templates.
+
+
ERB and JSP and ASP all have the fatal flaw of allowing code in the view. This is bad for a bunch of reasons. First,
+ it makes editing the templates difficult with HTML layout tools unless those tools are familiar with the syntax being
+ used. Second, there are "foreign" symbols in the layout, which tends to be less than optimal for the HTML designers.
+ (On the Rails side of things, every Rails team I've seen has a Ruby coder that also does the design. While this is
+ the norm in the Rails community, it is the exception when team sizes are more than 2 or 3.) Third, every single Rails,
+ JSP, and ASP project I've ever seen (and I've been seeing them for a very long time) has some non-trivial amount
+ of business logic creep into the display. Fourth, Scala has a very nice type system and when the type system is used
+ correctly, the compiler finds a lot of program errors, but when the code is buried in templates, one has a much more
+ difficult time using the powerful Scala compiler tools.
+
+
So, the static templates in Lift are strictly display only. They can be manipulated with standard design tools (e.g.,
+ Dreamweaver). They can never contain program logic.
+
+
Some asides.
+
+
First, I rejected using StringTemplate (or something like it) because it introduced some programming into the templating
+ mechanism and it would have taken a lot of work to make it XMLTemplate (and all of Lift's templating is XHTML and
+ makes use of Scala's excellent support of XML.)
+
+
Second, I've been referring to static templates. Lift has a little known and pretty much undocumented feature that
+ supports template generation from Scala code. One of these days, I'll document the feature and put up some examples.
+
+
Third, Rails' "controller first" dispatch mechanism makes the assumption that there is only one piece of "logic" on
+ the page and the rest is decoration. My experience doing web work is just the opposite. There are typically 3 or
+ more of pieces of logic on a page (dynamic menu bars, search boxes, shopping cart, real-time chat, etc.) and having
+ to choose which piece of logic make the "controller" is less than optimal.
+
+
So, the quintessential use of Lift's templates are as follows:
+
+
+
+
+
+
-/* ]]> */
-
-
The following is David Pollak's take on web framework view technology:
-
-
The Lift design is born out of my experience (both good and bad)
-with a variety of technologies including Rails.
-
I think the best paper on the subject is Terrence Parr's work on
-
-StringTemplate .
-
My first design goal with Lift was to make sure that no programming
-logic and no programming symbols make it into the static display
-templates.
-
ERB and JSP and ASP all have the fatal flaw of allowing code in the
-view. This is bad for a bunch of reasons. First, it makes editing
-the templates difficult with HTML layout tools unless those tools are
-familiar with the syntax being used. Second, there are "foreign"
-symbols in the layout, which tends to be less than optimal for the
-HTML designers. (On the Rails side of things, every Rails team I've
-seen has a Ruby coder that also does the design. While this is the
-norm in the Rails community, it is the exception when team sizes are
-more than 2 or 3.) Third, every single Rails, JSP, and ASP project
-I've ever seen (and I've been seeing them for a very long time) has
-some non-trivial amount of business logic creep into the display.
-Fourth, Scala has a very nice type system and when the type system is
-used correctly, the compiler finds a lot of program errors, but when
-the code is buried in templates, one has a much more difficult time
-using the powerful Scala compiler tools.
-
So, the static templates in Lift are strictly display only. They can
-be manipulated with standard design tools (e.g., Dreamweaver). They
-can never contain program logic.
-
Some asides.
-
First, I rejected using StringTemplate (or something like it) because
-it introduced some programming into the templating mechanism and it
-would have taken a lot of work to make it XMLTemplate (and all of
-Lift's templating is XHTML and makes use of Scala's excellent support
-of XML.)
-
Second, I've been referring to static templates. Lift has a little
-known and pretty much undocumented feature that supports template
-generation from Scala code. One of these days, I'll document the
-feature and put up some examples.
-
Third, Rails' "controller first" dispatch mechanism makes the
-assumption that there is only one piece of "logic" on the page and
-the rest is decoration. My experience doing web work is just the
-opposite. There are typically 3 or more of pieces of logic on a page
-(dynamic menu bars, search boxes, shopping cart, real-time chat,
-etc.) and having to choose which piece of logic make the "controller"
-is less than optimal.
-
So, the quintessential use of Lift's templates are as follows:
-
-
+ the new way
+
+<html>
+...
+ <form data-lift="Show?form=post" id="myForm">
+ <label for="name">Name</label>
+ <input type="text" name="name" id="name" placeholder="Name">
+ <label for="birthyear">Birthyear</label>
+ <select id="birthyear">
+ <option>2006</option>
+ <option>2007</option>
+ </select>
+ <input type="submit" value="Submit"/>
+ </form>
+ <div id="selectedyear"></div>
+ <div id="namevalue"></div>
+ <div id="wrappedNotice">
+ <div data-lift="Msgs"></div>
+ </div>
+...
+</html>
+
+
+
+ the old way
+
<html>
...
<lift:show.myForm form="post">
@@ -71,30 +124,72 @@
</lift:show.myForm>
...
-</html>
-
-
So we've got a Lift snippet invocation with the valid HTML form and
-some additional tags. So far (with the proper namespace
-declarations) this page is valid XHTML. This page can be viewed in a
-browser or opened and edited in Dreamweaver.
-
In Lift, the snippet is the equivalent of a Rails controller: it is
-the instantiation of a class and invocation of a method on the
-class. Because you can have multiple snippets on a page, you can
-call out multiple logic streams on a given page and there's no need
-to choose the "primary" logic stream.
-
The 'form="post"' attribute is a shortcut. It automatically wraps
-the enclosed XHTML in a <form method='post' target={current page...
-it's a post-back}>...</form> tag.
-
The <f:.../> tags are bind points for the business logic. They allow
-your snippet to easily replace the tag and its children with what is
-supposed to be displayed. This mechanism is a little heavier than
-Wicket's mechanism for binding display elements to logic and I've got
-a to-do to make Lift's mechanism work like Wickets as well... but
-that's a digression.
-
So, your Lift code will look like:
-
-
-
+</html>
+
+
So we've got a Lift snippet invocation with the valid HTML form and some additional tags. So far (with the proper namespace
+ declarations) this page is valid XHTML. This page can be viewed in a browser or opened and edited in Dreamweaver.
+
+
In Lift, the snippet is the equivalent of a Rails controller: it is the instantiation of a class and invocation of
+ a method on the class. Because you can have multiple snippets on a page, you can call out multiple logic streams
+ on a given page and there's no need to choose the "primary" logic stream.
+
+
The 'form="post"' attribute is a shortcut. It automatically wraps the enclosed XHTML in a <form method='post' target={current
+ page... it's a post-back}>...</form> tag.
+
+
The <f:.../> tags are bind points for the business logic. They allow your snippet to easily replace the tag and
+ its children with what is supposed to be displayed. This mechanism is a little heavier than Wicket's mechanism for
+ binding display elements to logic and I've got a to-do to make Lift's mechanism work like Wickets as well... but
+ that's a digression.
+
+
So, your Lift code will look like:
+
+
+
the new way
+
+class Show {
+ def render = {
+ "#birthyear" #> SHtml.ajaxSelect(Show.yearsOptions,
+ Show.yearsDefault,
+ Show.yearsHandler) &
+ "name=name" #> SHtml.ajaxText("", false, Show.nameHandler _) &
+ "type=submit" #> submit("Submit", Show.submitHandler _)
+ }
+}
+
+object Show {
+ private var name: String = ""
+ private var year: Int = 0
+ val years: Map[String, Int] = Map("2006" -> 2006,
+ "2007" -> 2007,
+ "2008" -> 2008,
+ "2009" -> 2009,
+ "2010" -> 2010)
+ val yearsOptions: List[(String, String)] = ("" -> "") :: years.keys
+ .map(p => (p, p))
+ .toList
+ val yearsDefault = Empty
+ // The function to call when an option is picked:
+ def yearsHandler(selected: String): JsCmd = {
+ this.year = years(selected)
+ S.notice("Selected year '" + years(selected) + "'")
+ SetHtml("selectedyear",
+ <div>{"Selected year '" + years(selected) + "'"}</div>)
+ }
+ def nameHandler(name: String): JsCmd = {
+ this.name = name
+ S.notice("The name is '" + name + "'")
+ SetHtml("namevalue", <div>{"The name is '" + name + "'"}</div>)
+ }
+ def submitHandler(): JsCmd = {
+ S.notice(
+ "The name and year was set to (" + this.name + "," + this.year + ")")
+ S.redirectTo("#myForm")
+ }
+}
+
+
+
the old way
+
class Show {
def myForm(xhtml: NodeSeq): NodeSeq = {
var name = ""
@@ -106,19 +201,30 @@
Empty, handleYear _))
}
}
+
-
-
Note that no display code has crept into the snippet. You've simply
-bound the HTML created by text() and select() to the <f:name/> and
-<f:year/> tags in the incoming XHTML.
-
Also, you've bound two functions (the anonymous function name = _
and
-handleYear) to the HTML form elements. When the form is POSTed,
-these functions (which are bound to local variables) will be
-statefully invoked.
-
If you are displaying a table rather than a
-form, then the same binding logic still works. For example:
-
-
+ Note that no display code has crept into the snippet. You've simply bound the HTML created by text() and select() to
+ the <f:name/> and <f:year/> tags in the incoming XHTML.
+
+ Also, you've bound two functions (the anonymous function
+ name = _
and handleYear) to the HTML form elements. When the form is POSTed, these functions (which are bound
+ to local variables) will be statefully invoked.
+
+ If you are displaying a table rather than a form, then the same binding logic still works. For example:
+
+
+ the new way
+
+<table data-lift="show:users">
+ <tr>
+ <td><span id="first_name">David</span></td>
+ <td><span id="last_name">Pollak</span></td>
+ </tr>
+</table>
+
+
+ the old way
+
<table>
<lift:snippet type="show:users">
@@ -127,26 +233,34 @@
</lift:snippet>
</table>
-
-
+
+
+
+
+
class Show {
def users(xhtml: NodeSeq): NodeSeq = Users.findAll.flatMap(user => bind("f",
xhtml, "first_name" --> user.firstName, "last_name" --> user.nameName))
}
+
+
-
-
If you take the time to clearly define the bind points, then you can
-have no display code at all in your snippets.
-
Can display logic slip into a snippet? Yes, and as you've seen and
-pointed out, the examples are less than optimal in this regard.
-
Has display logic ever crept into a method called from an ERB
-template? Yes, and very often it's a source of a potential Cross
-Site Scripting vulnerability.
-
Has business logic ever crept into an ERB template? Yes.
-
In Lift, display can creep into a snippet, but business logic cannot
-creep into a the static display template. Yes, your designers will
-still have to police putting display logic in the snippet code, but
-the coders will not have to police business logic in the templates.
-
+
If you take the time to clearly define the bind points, then you can have no display code at all in your snippets.
+
+
Can display logic slip into a snippet? Yes, and as you've seen and pointed out, the examples are less than optimal
+ in this regard.
+
+
Has display logic ever crept into a method called from an ERB template? Yes, and very often it's a source of a potential
+ Cross Site Scripting vulnerability.
+
+
Has business logic ever crept into an ERB template? Yes.
+
+
In Lift, display can creep into a snippet, but business logic cannot creep into a the static display template. Yes,
+ your designers will still have to police putting display logic in the snippet code, but the coders will not have
+ to police business logic in the templates.
+
+
-
+
+
+
\ No newline at end of file
diff --git a/combo/example/src/main/webapp/templating/surround.html b/combo/example/src/main/webapp/templating/surround.html
index 5c5a1d3..b3b2dbd 100644
--- a/combo/example/src/main/webapp/templating/surround.html
+++ b/combo/example/src/main/webapp/templating/surround.html
@@ -1,117 +1,65 @@
-
-
- Lift Example
-
-
-
-
+
+
+
Surround
+
+
+
+ Home
+
+
+ Templating
+
+ Surround
+
+
+
+ Lift supports surrounding a given section of a page with a template from another file. This allows you to have master page
+ templates or even section templates that are accessed by many different pages.
+
-
-
- Lift supports surrounding a given section of a page with a template
- from another file. This allows you to have master page templates
- or even section templates that are accessed by many different pages.
-
-
-
-
-
-
-<lift :surround with ="default" at ="content" >
+ <div data-lift="surround?with=default;at=content">
This is a simple page surrounded by the default template.
-</lift :surround >
-
-
-
-
-Using the <lift:surround> tag, you can surround the body with
-the contents of another template. The "with" attribute designates the
-name of the template. By convension, templates are stored in the
-/templates-hidden directory. Lift will not serve direct HTTP request
-from any directory that contains "-hidden". The "at" attribute specifies
-where the content should be placed in the loaded template. Lift will
-look for a <lift:bind name="..."/> tag in the target
-template and insert the body of the surround tag at the bind point.
-
+</div>
-
+
Using the
+ data-lift='surround...'
attribute in a tag, you can surround it's body with the contents of another template.
+ The
+ "with"
parameter designates the name of the template. By convension, templates are stored in the
+ /templates-hidden
directory. Lift will not serve direct HTTP request from any directory that contains
+ "-hidden"
. The
+ "at"
parameter specifies where the content should be placed in the loaded template. Lift will look for a tag
+ with a
+ id="content"
attribute in the target template and insert the body of the surround tag at the bind point.
+
-
-<html xmlns ="http://www.w3.org/1999/xhtml" xmlns :lift ='http://liftweb.net'>
- <head >
- <title >Lift Web Framework: <lift :Menu.title /></title >
-
- <lift :CSS.blueprint />
- <lift :CSS.fancyType />
- <script id ="jquery" src ="/classpath/jquery.js" type ="text/javascript" />
- <script id ="json" src ="/classpath/json.js" type ="text/javascript" />
- </head >
- <body >
- <div class ="menu" >
- <lift :menu.builder />
- </div >
- <div class ="messages" >
- <lift :Msgs />
- </div >
-
- <div class ="contents" >
- <lift :bind name ="content" />
- </div >
- </body >
-</html >
-
+
/templates-hidden/default.html
+
<html>
+<head>
+ <title data-lift="Menu.title">Lift Web Framework: %*%</title>
+ :
+</head>
+<body>
+ :
+ <div class="sidebar">
+ <span data-lift="menu.builder"></span>
+ </div>
+ :
+ <div data-lift="Msgs"></div>
+ :
+ <div id="content">The main content will get bound here</div>
+ :
+</body>
+</html>
-
-
-
+
+
+
\ No newline at end of file
From 4fa7200700d22dc626638c8ceb344de4a2484f29 Mon Sep 17 00:00:00 2001
From: karma4u101
Date: Sun, 31 Dec 2017 15:21:01 +0100
Subject: [PATCH 07/33] Templating / Web Services
Work done mostly on templating and web services sections.
---
combo/example/build.sbt | 2 +-
.../net/liftweb/example/snippet/Ajax.scala | 159 +++++++-------
.../liftweb/example/snippet/JSDialog.scala | 7 -
.../net/liftweb/example/snippet/Misc.scala | 95 ++++----
.../example/snippet/SimpleWizard.scala | 120 ++++++++++
.../example/snippet/SimpleWizard.scalaREM | 104 ---------
.../net/liftweb/example/view/XmlFun.scala | 3 +-
combo/example/src/main/webapp/ajax-form.html | 11 +-
combo/example/src/main/webapp/ajax.html | 146 ++++++-------
.../src/main/webapp/assets/css/app.css | 21 +-
combo/example/src/main/webapp/chat.html | 8 +-
combo/example/src/main/webapp/database.html | 8 +-
combo/example/src/main/webapp/form_ajax.html | 13 +-
.../example/src/main/webapp/interactive.html | 6 +-
combo/example/src/main/webapp/lazy.html | 74 ++++---
combo/example/src/main/webapp/parallel.html | 145 +++++-------
.../example/src/main/webapp/rhodeisland.html | 67 +++---
.../src/main/webapp/simple/delete.html | 9 +-
.../example/src/main/webapp/simple/index.html | 1 +
.../src/main/webapp/simple_wizard.html | 206 ++++++++++--------
.../src/main/webapp/stateless_json.html | 11 +-
.../src/main/webapp/templating/embed.html | 12 +-
.../main/webapp/templating/eval_order.html | 107 +++++----
.../src/main/webapp/templating/head.html | 130 +++++------
.../src/main/webapp/templating/index.html | 203 ++++++++---------
.../main/webapp/templating/selectomatic.html | 180 ++++++++-------
combo/example/src/main/webapp/ws.html | 205 ++++++++---------
27 files changed, 1043 insertions(+), 1010 deletions(-)
create mode 100644 combo/example/src/main/scala/net/liftweb/example/snippet/SimpleWizard.scala
delete mode 100644 combo/example/src/main/scala/net/liftweb/example/snippet/SimpleWizard.scalaREM
diff --git a/combo/example/build.sbt b/combo/example/build.sbt
index 0a88075..609a9e1 100644
--- a/combo/example/build.sbt
+++ b/combo/example/build.sbt
@@ -4,7 +4,7 @@ organization := "net.liftweb"
name := "demo"
-version := "0.5.1-SNAPSHOT"
+version := "0.5.2-SNAPSHOT"
scalaVersion := "2.11.11" //2.12.2
diff --git a/combo/example/src/main/scala/net/liftweb/example/snippet/Ajax.scala b/combo/example/src/main/scala/net/liftweb/example/snippet/Ajax.scala
index 423206a..70ddb6a 100644
--- a/combo/example/src/main/scala/net/liftweb/example/snippet/Ajax.scala
+++ b/combo/example/src/main/scala/net/liftweb/example/snippet/Ajax.scala
@@ -14,100 +14,93 @@
* limitations under the License.
*/
-package net.liftweb {
- package example {
- package snippet {
+package net.liftweb.example.snippet
- import net.liftweb.http._
- import net.liftmodules.widgets.autocomplete._
- import S._
- import SHtml._
- import js._
- import js.jquery._
- import JqJsCmds._
- import JsCmds._
- import common._
- import util._
- import Helpers._
- import _root_.scala.xml.{Text, NodeSeq}
+import net.liftweb._
+import http._
+import SHtml._
+import js._
+import js.jquery._
+import JqJsCmds._
+import JsCmds._
+import common._
+import util._
+import Helpers._
+import net.liftmodules.widgets.autocomplete._
+import scala.xml.{Text, NodeSeq}
- class Ajax extends Loggable {
+class Ajax extends Loggable {
- def sample(xhtml: NodeSeq): NodeSeq = {
- // local state for the counter
- var cnt = 0
+ def sample(xhtml: NodeSeq): NodeSeq = {
+ // local state for the counter
+ var cnt = 0
- // get the id of some elements to update
- val spanName: String = S.attr("id_name") openOr "cnt_id"
- val msgName: String = S.attr("id_msgs") openOr "messages"
+ // get the id of some elements to update
+ val spanName: String = S.attr("id_name") openOr "cnt_id"
+ val msgName: String = S.attr("id_msgs") openOr "messages"
- // build up an ajax tag to increment the counter
- def doClicker(text: NodeSeq) =
- a(() => { cnt = cnt + 1; SetHtml(spanName, Text(cnt.toString)) },
- text)
+ // build up an ajax tag to increment the counter
+ def doClicker(text: NodeSeq) =
+ a(() => { cnt = cnt + 1; SetHtml(spanName, Text(cnt.toString)) }, text)
- // create an ajax select box
- def doSelect(msg: NodeSeq) =
- ajaxSelect(
- (1 to 50).toList.map(i => (i.toString, i.toString)),
- Full(1.toString),
- v => {
- val selectBind = "#selNumber" #> Text(v)
- DisplayMessage(
- msgName,
- {selectBind(msg)} ,
- 5 seconds,
- 1 second
- )
- },
- "class" -> "form-control"
- )
+ // create an ajax select box
+ def doSelect(msg: NodeSeq) =
+ ajaxSelect(
+ (1 to 50).toList.map(i => (i.toString, i.toString)),
+ Full(1.toString),
+ v => {
+ val selectBind = "#selNumber" #> Text(v)
+ DisplayMessage(
+ msgName,
+ {selectBind(msg)} ,
+ 5 seconds,
+ 1 second
+ )
+ },
+ "class" -> "form-control"
+ )
- // build up an ajax text box
- def doText(msg: NodeSeq) =
- ajaxText(
- "",
- v => {
- val textBind = "#textValue" #> Text(v)
- DisplayMessage(msgName,
- {textBind(msg)} ,
- 6 seconds,
- 1 second)
- },
- "class" -> "form-control"
- )
+ // build up an ajax text box
+ def doText(msg: NodeSeq) =
+ ajaxText(
+ "",
+ v => {
+ val textBind = "#textValue" #> Text(v)
+ DisplayMessage(msgName,
+ {textBind(msg)} ,
+ 6 seconds,
+ 1 second)
+ },
+ "class" -> "form-control"
+ )
- // bind the view to the functionality
- val viewBind = {
- "#ajaxClicker" #> doClicker _ &
- "#ajaxSelect" #> doSelect _ &
- "#ajaxText" #> doText _ &
- "#ajaxAuto" #> AutoComplete("",
- buildQuery _,
- (x:String) => (),
- "class" -> "form-control")
- }
- viewBind(xhtml)
- }
+ // bind the view to the functionality
+ val viewBind = {
+ "#ajaxClicker" #> doClicker _ &
+ "#ajaxSelect" #> doSelect _ &
+ "#ajaxText" #> doText _ &
+ "#ajaxAuto" #> AutoComplete("",
+ buildQuery _,
+ (x: String) => (),
+ "class" -> "form-control")
+ }
+ viewBind(xhtml)
+ }
- private def buildQuery(current: String, limit: Int): Seq[String] = {
- logger.info(
- "Checking on server side with " + current + " limit " + limit)
- (1 to limit).map(n => current + "" + n)
- }
+ private def buildQuery(current: String, limit: Int): Seq[String] = {
+ logger.info("Checking on server side with " + current + " limit " + limit)
+ (1 to limit).map(n => current + "" + n)
+ }
- def time = Text(now.toString)
+ def time = Text(now.toString)
- def buttonClick = {
- import js.JE._
+ def buttonClick = {
+ import js.JE._
- "* [onclick]" #> SHtml.ajaxCall(
- ValById("the_input"),
- s =>
- SetHtml("bcmessages",
- Latest Button click was with text box value '{s}' ))
- }
- }
- }
+ "* [onclick]" #> SHtml.ajaxCall(
+ ValById("the_input"),
+ s =>
+ SetHtml("bcmessages",
+ Latest Button click was with text box value '{s}' ))
}
}
diff --git a/combo/example/src/main/scala/net/liftweb/example/snippet/JSDialog.scala b/combo/example/src/main/scala/net/liftweb/example/snippet/JSDialog.scala
index 1196133..08a6d60 100644
--- a/combo/example/src/main/scala/net/liftweb/example/snippet/JSDialog.scala
+++ b/combo/example/src/main/scala/net/liftweb/example/snippet/JSDialog.scala
@@ -43,13 +43,6 @@ package net.liftweb {
Alert("Couldn't find _jsdialog_confirm template"),
"class" -> "btn btn-primary")
- /* def button(in: NodeSeq) =
- ajaxButton(in,
- () =>
- S.runTemplate(List("_bsdialog_confirm")).map(ns => JqSetHtml("modal",ns)) openOr
- Alert("Couldn't find _jsdialog_confirm template"),
- "class" -> "btn btn-primary", "data-toggle" -> "modal", "data-target" -> "modal") */
-
// the template needs to bind to either server-side behavior
// and unblock the UI
def confirm = {
diff --git a/combo/example/src/main/scala/net/liftweb/example/snippet/Misc.scala b/combo/example/src/main/scala/net/liftweb/example/snippet/Misc.scala
index e457727..6c9d0fd 100644
--- a/combo/example/src/main/scala/net/liftweb/example/snippet/Misc.scala
+++ b/combo/example/src/main/scala/net/liftweb/example/snippet/Misc.scala
@@ -38,30 +38,36 @@ class Misc {
private val logger = Logger(classOf[Misc])
/**
- * Get the XHTML containing a list of users
- */
+ * Get the XHTML containing a list of users
+ */
def users: NodeSeq = {
User.find() match {
- case Empty => User.create.firstName("Archer").lastName("Dog").email("archer@dogfood.com").password("mypassword").save
+ case Empty =>
+ User.create
+ .firstName("Archer")
+ .lastName("Dog")
+ .email("archer@dogfood.com")
+ .password("mypassword")
+ .save
case _ =>
}
// the header
{User.htmlHeaders}Edit Delete ::
- // get and display each of the users
- User.findAll(OrderBy(User.id, Ascending)).flatMap(u => {u.htmlLine}
+ // get and display each of the users
+ User.findAll(OrderBy(User.id, Ascending)).flatMap(u => {u.htmlLine}
{link("/simple/edit", () => selectedUser(Full(u)), Text("Edit"), "class" -> "btn btn-sm btn-outline-secondary")}
{link("/simple/delete", () => selectedUser(Full(u)), Text("Delete"), "class" -> "btn btn-sm btn-outline-secondary")}
)
}
/**
- * Confirm deleting a user
- */
+ * Confirm deleting a user
+ */
def confirmDelete(xhtml: Group): NodeSeq = {
(for (user <- selectedUser.is) // find the user
- yield {
+ yield {
def deleteUser() {
- notice("User "+(user.firstName+" "+user.lastName)+" deleted")
+ notice("User " + (user.firstName + " " + user.lastName) + " deleted")
user.delete_!
redirectTo("/simple/index.html")
}
@@ -72,17 +78,16 @@ class Misc {
// in the current content)
val bindDelete = {
"#username" #> (user.firstName.get + " " + user.lastName.get) &
- "#delete" #> submit(
- "Yes delete",
- deleteUser _,
- "type" -> "button",
- "class" -> "btn btn-danger")
+ "#delete" #> submit("Yes delete",
+ deleteUser _,
+ "type" -> "button",
+ "class" -> "btn btn-danger")
}
- bindDelete(xhtml)
+ bindDelete(xhtml)
// if the was no ID or the user couldn't be found,
// display an error and redirect
- }) openOr {error("User not found"); redirectTo("/simple/index.html")}
+ }) openOr { error("User not found"); redirectTo("/simple/index.html") }
}
// called when the form is submitted
@@ -91,53 +96,54 @@ class Misc {
// back to the "list" page
case Nil => user.save; redirectTo("/simple/index.html")
- // oops... validation errors
- // display the errors and make sure our selected user is still the same
+ // oops... validation errors
+ // display the errors and make sure our selected user is still the same
case x => {
- logger.debug("SaveUser got a validation error="+x.toString())
+ logger.debug("SaveUser got a validation error=" + x.toString())
S.error(x)
selectedUser(Full(user))
}
}
/**
- * Add a user
- */
+ * Add a user
+ */
def add(xhtml: Group): NodeSeq =
- selectedUser.is.openOr(new User).toForm(Empty, saveUser _) ++
+ selectedUser.is.openOr(new User).toForm(Empty, saveUser _) ++
Cancel
Create
/**
- * Edit a user
- */
+ * Edit a user
+ */
def edit(xhtml: Group): NodeSeq =
- selectedUser.map(_.
- // get the form data for the user and when the form
- // is submitted, call the passed function.
- // That means, when the user submits the form,
- // the fields that were typed into will be populated into
- // "user" and "saveUser" will be called. The
- // form fields are bound to the model's fields by this
- // call.
- toForm(Empty, saveUser _) ++
+ selectedUser.map(
+ _.
+ // get the form data for the user and when the form
+ // is submitted, call the passed function.
+ // That means, when the user submits the form,
+ // the fields that were typed into will be populated into
+ // "user" and "saveUser" will be called. The
+ // form fields are bound to the model's fields by this
+ // call.
+ toForm(Empty, saveUser _) ++
Cancel
Save
- // bail out if the ID is not supplied or the user's not found
- ) openOr {error("User not found"); redirectTo("/simple/index.html")}
+ // bail out if the ID is not supplied or the user's not found
+ ) openOr { error("User not found"); redirectTo("/simple/index.html") }
// the request-local variable that hold the file parameter
private object theUpload extends RequestVar[Box[FileParamHolder]](Empty)
/**
- * Bind the appropriate XHTML to the form
- */
+ * Bind the appropriate XHTML to the form
+ */
/*TODO PPE REM
- *
- * */
+ *
+ * */
/*
def upload(xhtml: Group): NodeSeq =
if (S.get_?) bind("ul", chooseTemplate("choose", "get", xhtml),
@@ -148,16 +154,19 @@ class Misc {
"length" -> theUpload.is.map(v => Text(v.file.length.toString)),
"md5" -> theUpload.is.map(v => Text(hexEncode(md5(v.file))))
);
- */
+ */
def lang = {
"#lang" #> locale.getDisplayLanguage(locale) &
- "#select" #> SHtml.selectObj(locales.map(lo => (lo, lo.getDisplayName)),
- definedLocale, setLocale)
+ "#select" #> SHtml.selectObj(locales.map(lo => (lo, lo.getDisplayName)),
+ definedLocale,
+ setLocale,
+ "class" -> "form-control")
}
private def locales =
- Locale.getAvailableLocales.toList.sortWith(_.getDisplayName < _.getDisplayName)
+ Locale.getAvailableLocales.toList
+ .sortWith(_.getDisplayName < _.getDisplayName)
private def setLocale(loc: Locale) = definedLocale(Full(loc))
}
diff --git a/combo/example/src/main/scala/net/liftweb/example/snippet/SimpleWizard.scala b/combo/example/src/main/scala/net/liftweb/example/snippet/SimpleWizard.scala
new file mode 100644
index 0000000..3954340
--- /dev/null
+++ b/combo/example/src/main/scala/net/liftweb/example/snippet/SimpleWizard.scala
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2007-2010 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.example.snippet
+
+import _root_.net.liftweb.http._
+import _root_.net.liftweb.http.S
+import _root_.net.liftweb.http.SHtml._
+import _root_.net.liftweb.util.Helpers._
+import _root_.scala.xml.{NodeSeq}
+
+/**
+ * The Arc Challenge is Paul Graham's quest for web framework concision.
+ *
+ * http://www.paulgraham.com/arcchallenge.html
+ *
+ * This is one potential lift-based solution to it using StatefulSnippets.
+ * There are doubtless many other ways.
+ *
+ * @author: Steve Jenson
+ */
+class SimpleWizard extends StatefulSnippet {
+ val fromWhence = S.referer openOr "/"
+ var dispatch: DispatchIt = {
+ case _ =>
+ xhtml =>
+ pageOne
+ }
+ var name = ""
+ var quest = ""
+ var color = ""
+
+ private def template(name: String, f: NodeSeq => NodeSeq): NodeSeq =
+ Templates(List("templating") ::: List(name)).map(f) openOr
+ NodeSeq.Empty
+
+ /**
+ * pageOne -- Ask the name
+ */
+ def pageOne = {
+ def validate() {
+ this.registerThisSnippet()
+ if (name.length < 2) S.error(S.?("Name too short"))
+ else
+ dispatch = {
+ case _ =>
+ xhtml =>
+ pageTwo
+ }
+ }
+
+ template(
+ "pageOne",
+ ("#name" replaceWith text(name, name = _, "class" -> "form-control")) &
+ ("#submit" replaceWith submit(S ? "Next",
+ validate,
+ "class" -> "btn btn-primary")))
+ }
+
+ /**
+ * pageTwo -- Ask the quest
+ */
+ def pageTwo = {
+ def validate() {
+ this.registerThisSnippet()
+ if (quest.length < 2) S.error(S.?("Quest too short"))
+ else
+ dispatch = {
+ case _ =>
+ xhtml =>
+ pageThree
+ }
+ }
+
+ template(
+ "pageTwo",
+ ("#quest" replaceWith text(quest, quest = _, "class" -> "form-control")) &
+ ("#submit" replaceWith submit(S ? "Next",
+ validate,
+ "class" -> "btn btn-primary")))
+ }
+
+ /**
+ * pageThree -- Ask the color
+ */
+ def pageThree = {
+ def validate() {
+ this.registerThisSnippet()
+ if (!List("red", "yellow", "blue").contains(color.toLowerCase))
+ S.error(S.?("Color not red, yellow or blue"))
+ else {
+ S.notice(
+ "You, " + name + " on the quest " + quest + " may cross the bridge of sorrows")
+ S.redirectTo(fromWhence)
+ }
+ }
+
+ template(
+ "pageThree",
+ ("#color" replaceWith text(color, color = _, "class" -> "form-control")) &
+ ("#submit" replaceWith submit(S ? "Finish",
+ validate,
+ "class" -> "btn btn-primary"))
+ )
+ }
+
+}
diff --git a/combo/example/src/main/scala/net/liftweb/example/snippet/SimpleWizard.scalaREM b/combo/example/src/main/scala/net/liftweb/example/snippet/SimpleWizard.scalaREM
deleted file mode 100644
index bca42bf..0000000
--- a/combo/example/src/main/scala/net/liftweb/example/snippet/SimpleWizard.scalaREM
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2007-2010 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 example {
-package snippet {
-
-import _root_.net.liftweb.example.model._
-import _root_.net.liftweb.http._
-import _root_.net.liftweb.http.S
-import _root_.net.liftweb.mapper._
-import _root_.net.liftweb.http.S._
-import _root_.net.liftweb.http.SHtml._
-import _root_.net.liftweb.util.Helpers._
-import _root_.net.liftweb.common._
-import _root_.net.liftweb.util._
-import _root_.scala.xml.{NodeSeq, Text, Group}
-
-/**
- * The Arc Challenge is Paul Graham's quest for web framework concision.
- *
- * http://www.paulgraham.com/arcchallenge.html
- *
- * This is one potential lift-based solution to it using StatefulSnippets.
- * There are doubtless many other ways.
- *
- * @author: Steve Jenson
- */
-class SimpleWizard extends StatefulSnippet {
- val fromWhence = S.referer openOr "/"
- var dispatch: DispatchIt = {case _ => xhtml => pageOne}
- var name = ""
- var quest = ""
- var color = ""
-
- private def template(name: String, f: NodeSeq => NodeSeq): NodeSeq =
- Templates(List("templating") ::: List(name)).map(f) openOr
- NodeSeq.Empty
-
- /**
- * pageOne -- Ask the name
- */
- def pageOne = {
- def validate() {
- this.registerThisSnippet()
- if (name.length < 2) S.error(S.?("Name too short"))
- else dispatch = {case _ => xhtml => pageTwo}
- }
-
- template("pageOne",
- ("#name" replaceWith text(name, name = _)) &
- ("#submit" replaceWith submit(S ? "Next", validate)))
- }
-
- /**
- * pageTwo -- Ask the quest
- */
- def pageTwo = {
- def validate() {
- this.registerThisSnippet()
- if (quest.length < 2) S.error(S.?("Quest too short"))
- else dispatch = {case _ => xhtml => pageThree}
- }
-
- template("pageTwo",
- ("#quest" replaceWith text(quest, quest = _)) &
- ("#submit" replaceWith submit(S ? "Next", validate)))
- }
-
- /**
- * pageThree -- Ask the color
- */
- def pageThree = {
- def validate() {
- this.registerThisSnippet()
- if (!List("red", "yellow", "blue").contains(color.toLowerCase)) S.error(S.?("Color not red, yellow or blue"))
- else {
- S.notice("You, "+name+" on the quest "+quest+" may cross the bridge of sorrows")
- S.redirectTo(fromWhence)
- }
- }
-
- template("pageThree",
- ("#color" replaceWith text(color, color = _)) &
- ("#submit" replaceWith submit(S ? "Finish", validate)))
- }
-
-}
-}
-}
-}
diff --git a/combo/example/src/main/scala/net/liftweb/example/view/XmlFun.scala b/combo/example/src/main/scala/net/liftweb/example/view/XmlFun.scala
index 45448cc..32f1154 100644
--- a/combo/example/src/main/scala/net/liftweb/example/view/XmlFun.scala
+++ b/combo/example/src/main/scala/net/liftweb/example/view/XmlFun.scala
@@ -51,7 +51,8 @@ class XmlFun extends LiftView {
XML Fun
- The XML is
+
+ The XML is
{addresses.map{e => Text(e.toString) :: :: Nil}}
The count for {toCount} nodes is {countryCount(toCount, addresses)}
Count US addresses.
diff --git a/combo/example/src/main/webapp/ajax-form.html b/combo/example/src/main/webapp/ajax-form.html
index e126781..72eb94f 100644
--- a/combo/example/src/main/webapp/ajax-form.html
+++ b/combo/example/src/main/webapp/ajax-form.html
@@ -38,9 +38,10 @@ AJAX Form Update
- Here's the code:
-
-class AjaxForm {
+
+ The
+ Lift Scala code
+ class AjaxForm {
var state = AjaxForm.state
var city = ""
@@ -87,9 +88,7 @@ AJAX Form Update
def citiesFor(state: String): List[String] =
citiesAndStates.filter(_._1 == state).map(_._2)
-}
-
-
+}
diff --git a/combo/example/src/main/webapp/ajax.html b/combo/example/src/main/webapp/ajax.html
index 6bb9bb8..ec8152c 100644
--- a/combo/example/src/main/webapp/ajax.html
+++ b/combo/example/src/main/webapp/ajax.html
@@ -80,89 +80,85 @@ AJAX Samples
- The
- Lift Scala code to render the controls:
-
-class Ajax extends Loggable {
-
- def sample(xhtml: NodeSeq): NodeSeq = {
- // local state for the counter
- var cnt = 0
-
- // get the id of some elements to update
- val spanName: String = S.attr("id_name") openOr "cnt_id"
- val msgName: String = S.attr("id_msgs") openOr "messages"
-
- // build up an ajax <a> tag to increment the counter
- def doClicker(text: NodeSeq) =
- a(() => { cnt = cnt + 1; SetHtml(spanName, Text(cnt.toString)) },
- text)
-
- // create an ajax select box
- def doSelect(msg: NodeSeq) =
- ajaxSelect(
- (1 to 50).toList.map(i => (i.toString, i.toString)),
- Full(1.toString),
- v => {
- val selectBind = "#selNumber" #> Text(v)
- DisplayMessage(
- msgName,
- <span>{selectBind(msg)}</span>,
- 5 seconds,
- 1 second
- )
- },
- "class" -> "form-control"
- )
-
- // build up an ajax text box
- def doText(msg: NodeSeq) =
- ajaxText(
- "",
- v => {
- val textBind = "#textValue" #> Text(v)
- DisplayMessage(msgName,
- <span>{textBind(msg)}</span>,
- 6 seconds,
- 1 second)
- },
- "class" -> "form-control"
- )
-
- // bind the view to the functionality
- val viewBind = {
- "#ajaxClicker" #> doClicker _ &
- "#ajaxSelect" #> doSelect _ &
- "#ajaxText" #> doText _ &
- "#ajaxAuto" #> AutoComplete("",
- buildQuery _,
- _ => (),
- "class" -> "form-control")
- }
- viewBind(xhtml)
+ The
+ Lift Scala code
+ class Ajax extends Loggable {
+
+ def sample(xhtml: NodeSeq): NodeSeq = {
+ // local state for the counter
+ var cnt = 0
+
+ // get the id of some elements to update
+ val spanName: String = S.attr("id_name") openOr "cnt_id"
+ val msgName: String = S.attr("id_msgs") openOr "messages"
+
+ // build up an ajax <a> tag to increment the counter
+ def doClicker(text: NodeSeq) =
+ a(() => { cnt = cnt + 1; SetHtml(spanName, Text(cnt.toString)) }, text)
+
+ // create an ajax select box
+ def doSelect(msg: NodeSeq) =
+ ajaxSelect(
+ (1 to 50).toList.map(i => (i.toString, i.toString)),
+ Full(1.toString),
+ v => {
+ val selectBind = "#selNumber" #> Text(v)
+ DisplayMessage(
+ msgName,
+ <span>{selectBind(msg)}</span>,
+ 5 seconds,
+ 1 second
+ )
+ },
+ "class" -> "form-control"
+ )
+
+ // build up an ajax text box
+ def doText(msg: NodeSeq) =
+ ajaxText(
+ "",
+ v => {
+ val textBind = "#textValue" #> Text(v)
+ DisplayMessage(msgName,
+ <span>{textBind(msg)}</span>,
+ 6 seconds,
+ 1 second)
+ },
+ "class" -> "form-control"
+ )
+
+ // bind the view to the functionality
+ val viewBind = {
+ "#ajaxClicker" #> doClicker _ &
+ "#ajaxSelect" #> doSelect _ &
+ "#ajaxText" #> doText _ &
+ "#ajaxAuto" #> AutoComplete("",
+ buildQuery _,
+ (x: String) => (),
+ "class" -> "form-control")
}
+ viewBind(xhtml)
+ }
- private def buildQuery(current: String, limit: Int): Seq[String] = {
- logger.info(
- "Checking on server side with " + current + " limit " + limit)
- (1 to limit).map(n => current + "" + n)
- }
+ private def buildQuery(current: String, limit: Int): Seq[String] = {
+ logger.info("Checking on server side with " + current + " limit " + limit)
+ (1 to limit).map(n => current + "" + n)
+ }
- def time = Text(now.toString)
+ def time = Text(now.toString)
- def buttonClick = {
- import js.JE._
+ def buttonClick = {
+ import js.JE._
- "* [onclick]" #> SHtml.ajaxCall(
- ValById("the_input"),
- s =>
- SetHtml("bcmessages",
- <i>Latest Button click was with text box value '{s}'</i>))
- }
+ "* [onclick]" #> SHtml.ajaxCall(
+ ValById("the_input"),
+ s =>
+ SetHtml("bcmessages",
+ <i>Latest Button click was with text box value '{s}'</i>))
}
-
+}
diff --git a/combo/example/src/main/webapp/assets/css/app.css b/combo/example/src/main/webapp/assets/css/app.css
index 2182261..818c3c3 100644
--- a/combo/example/src/main/webapp/assets/css/app.css
+++ b/combo/example/src/main/webapp/assets/css/app.css
@@ -84,7 +84,9 @@
border-left: none;
}
-
+.dpp_stuff p {
+ padding-left: 15px;
+}
/*Lift stuff*/
@@ -134,6 +136,23 @@
border-bottom: 1px solid #ccc;
}
+
+.bd-callout {
+ padding: 1.25rem;
+ margin-top: 1.25rem;
+ margin-bottom: 1.25rem;
+ border: 1px solid #eee;
+ border-left-width: .25rem;
+ border-radius: .25rem;
+}
+
+.bd-callout-info {
+ border-left-color: #5bc0de;
+}
+.bd-callout-warning {
+ border-left-color: #f0ad4e;
+}
+
/* bootstrap overrides */
.breadcrumb {
font-size: 0.8rem;
diff --git a/combo/example/src/main/webapp/chat.html b/combo/example/src/main/webapp/chat.html
index a29e061..15b8db5 100644
--- a/combo/example/src/main/webapp/chat.html
+++ b/combo/example/src/main/webapp/chat.html
@@ -51,8 +51,9 @@ Comet Chat
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 Chat extends CometActor with CometListener {
+ The
+ Lift Scala code
+ class Chat extends CometActor with CometListener {
private var userName = ""
private var chats: List[ChatLine] = Nil
@@ -134,8 +135,7 @@ Comet Chat
}
}
-}
-
+}
This example demonstrates the power of Scala's Actors and
diff --git a/combo/example/src/main/webapp/database.html b/combo/example/src/main/webapp/database.html
index 059365a..6ab9fac 100644
--- a/combo/example/src/main/webapp/database.html
+++ b/combo/example/src/main/webapp/database.html
@@ -32,8 +32,9 @@
Database
to create more records.
-
-/**
+ The
+ Lift Scala code
+ /**
* The singleton that has methods for accessing the database
*/
object User extends User with KeyedMetaMapper[Long, User] {
@@ -57,8 +58,7 @@ Database
override def textareaCols = 50
override def displayName = "Personal Essay"
}
-}
-
+}
For this little bit of work, we get a complete user with first name, last name, password, email, and a personal essay.
Each of the fields knows how to validate itself. The User (and any other "Mapped" class) knows how to Create,
diff --git a/combo/example/src/main/webapp/form_ajax.html b/combo/example/src/main/webapp/form_ajax.html
index 9251310..fb1b060 100644
--- a/combo/example/src/main/webapp/form_ajax.html
+++ b/combo/example/src/main/webapp/form_ajax.html
@@ -32,7 +32,7 @@
Example: Forms with Ajax callback on form element blur
diff --git a/combo/example/src/main/webapp/interactive.html b/combo/example/src/main/webapp/interactive.html
index b06929b..0e4a05d 100644
--- a/combo/example/src/main/webapp/interactive.html
+++ b/combo/example/src/main/webapp/interactive.html
@@ -29,8 +29,7 @@ Ajax
Comet
Lift supports Comet-style long polling with very little work on the part of the developer. Here's the code the implements
the clock that you see in this demo:
-
-class ExampleClock(initSession: LiftSession,
+ class ExampleClock(initSession: LiftSession,
initType: Box[String],
initName: Box[String],
initDefaultXml: NodeSeq,
@@ -56,8 +55,7 @@ Comet
initCometActor(creationInfo)
}
-case object Tick
-
+case object Tick