From 1d1aae11ede3ad4a7c317a0eb781906bc211bfbc Mon Sep 17 00:00:00 2001 From: Torsten Uhlmann Date: Tue, 22 Feb 2011 17:28:59 +0100 Subject: [PATCH] Refinements in the eventhings port. Created some more bridge classes. --- project/build/LiftProject.scala | 26 + src/main/java/bootstrap/liftweb/Boot.java | 4 + .../net/liftweb/seventhings/lib/HelpersJ.java | 6 +- .../net/liftweb/seventhings/lib/ListJ.java | 9 + .../net/liftweb/seventhings/lib/Matcher.java | 79 +++ .../liftweb/seventhings/snippet/LongTime.java | 15 +- .../liftweb/seventhings/snippet/MyWizard.java | 82 +++ .../seventhings/snippet/MyWizardJava.java | 66 --- .../src/java/bootstrap/liftweb/Boot.java | 100 ++++ .../net/liftweb/seventhings/comet/Chat.java | 34 ++ .../liftweb/seventhings/comet/ChatServer.java | 51 ++ .../net/liftweb/seventhings/comet/Yacker.java | 35 ++ .../net/liftweb/seventhings/lib/BoxJ.java | 11 + .../net/liftweb/seventhings/lib/HelpersJ.java | 12 + .../liftweb/seventhings/lib/JqJsCmdsJ.java | 21 + .../net/liftweb/seventhings/lib/ListJ.java | 20 + .../net/liftweb/seventhings/lib/Matcher.java | 79 +++ .../liftweb/seventhings/lib/TopScopeJ.java | 13 + .../liftweb/seventhings/lib/WiringUIJ.java | 15 + .../net/liftweb/seventhings/lib/XmlJ.java | 66 +++ .../net/liftweb/seventhings/lib/XmlNullJ.java | 22 + .../seventhings/snippet/AjaxRunner.java | 31 ++ .../liftweb/seventhings/snippet/ChatIn.java | 49 ++ .../liftweb/seventhings/snippet/FetchAd.java | 25 + .../seventhings/snippet/InvoiceWiring.java | 303 +++++++++++ .../liftweb/seventhings/snippet/LongTime.java | 35 ++ .../liftweb/seventhings/snippet/MyWizard.java | 82 +++ .../liftweb/seventhings/snippet/ShowCode.java | 146 ++++++ .../scala/net/liftweb/seventhings/comet/.keep | 0 .../liftweb/seventhings/lib/BoxJBridge.scala | 10 + .../seventhings/lib/HelpersJBridge.scala | 14 + .../seventhings/lib/JqJsCmdsJBridge.scala | 7 + .../seventhings/lib/TopScopeJBridge.scala | 10 + .../seventhings/lib/WiringUIBridge.scala | 10 + .../net/liftweb/seventhings/lib/WizardJ.scala | 21 + .../liftweb/seventhings/lib/XmlJBridge.scala | 22 + .../seventhings/lib/XmlNullJBridge.scala | 15 + .../scala/net/liftweb/seventhings/model/.keep | 0 .../seventhings/snippet/InvoiceWiring.scala | 113 ++++ .../seventhings/snippet/MyWizard.scala | 5 +- .../seventhings/snippet/MyWizardScala.scala | 64 +++ .../seventhings/snippet/ShowCodeScala.scala | 67 +++ .../scala/net/liftweb/seventhings/view/.keep | 0 src/main/resources/src/webapp/WEB-INF/web.xml | 21 + src/main/resources/src/webapp/comet.html | 137 +++++ src/main/resources/src/webapp/css/shCore.css | 226 ++++++++ .../src/webapp/css/shThemeDefault.css | 117 +++++ .../src/webapp/images/ajax-loader.gif | Bin 0 -> 2608 bytes src/main/resources/src/webapp/index.html | 34 ++ src/main/resources/src/webapp/lazy.html | 63 +++ src/main/resources/src/webapp/parallel.html | 103 ++++ .../src/webapp/scripts/jquery.blockUI.js | 490 ++++++++++++++++++ .../src/webapp/scripts/shBrushBash.js | 30 ++ .../src/webapp/scripts/shBrushJava.js | 57 ++ .../src/webapp/scripts/shBrushScala.js | 51 ++ .../src/webapp/scripts/shBrushXml.js | 69 +++ .../resources/src/webapp/scripts/shCore.js | 17 + src/main/resources/src/webapp/security.html | 68 +++ .../resources/src/webapp/static/index.html | 5 + .../src/webapp/templates-hidden/default.html | 127 +++++ .../webapp/templates-hidden/wizard-all.html | 57 ++ src/main/resources/src/webapp/templates.html | 62 +++ src/main/resources/src/webapp/wiring.html | 105 ++++ src/main/resources/src/webapp/wizard.html | 77 +++ .../seventhings/lib/HelpersJBridge.scala | 14 + .../net/liftweb/seventhings/lib/WizardJ.scala | 13 +- .../seventhings/snippet/MyWizardScala.scala | 64 +++ 67 files changed, 3717 insertions(+), 85 deletions(-) create mode 100644 project/build/LiftProject.scala create mode 100644 src/main/java/net/liftweb/seventhings/lib/Matcher.java create mode 100644 src/main/java/net/liftweb/seventhings/snippet/MyWizard.java delete mode 100644 src/main/java/net/liftweb/seventhings/snippet/MyWizardJava.java create mode 100644 src/main/resources/src/java/bootstrap/liftweb/Boot.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/comet/Chat.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/comet/ChatServer.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/comet/Yacker.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/lib/BoxJ.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/lib/HelpersJ.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/lib/JqJsCmdsJ.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/lib/ListJ.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/lib/Matcher.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/lib/TopScopeJ.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/lib/WiringUIJ.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/lib/XmlJ.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/lib/XmlNullJ.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/snippet/AjaxRunner.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/snippet/ChatIn.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/snippet/FetchAd.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/snippet/InvoiceWiring.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/snippet/LongTime.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/snippet/MyWizard.java create mode 100644 src/main/resources/src/java/net/liftweb/seventhings/snippet/ShowCode.java create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/comet/.keep create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/lib/BoxJBridge.scala create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/lib/HelpersJBridge.scala create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/lib/JqJsCmdsJBridge.scala create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/lib/TopScopeJBridge.scala create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/lib/WiringUIBridge.scala create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/lib/WizardJ.scala create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/lib/XmlJBridge.scala create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/lib/XmlNullJBridge.scala create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/model/.keep create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/snippet/InvoiceWiring.scala rename src/main/{ => resources/src}/scala/net/liftweb/seventhings/snippet/MyWizard.scala (93%) create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/snippet/MyWizardScala.scala create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/snippet/ShowCodeScala.scala create mode 100644 src/main/resources/src/scala/net/liftweb/seventhings/view/.keep create mode 100644 src/main/resources/src/webapp/WEB-INF/web.xml create mode 100644 src/main/resources/src/webapp/comet.html create mode 100644 src/main/resources/src/webapp/css/shCore.css create mode 100644 src/main/resources/src/webapp/css/shThemeDefault.css create mode 100644 src/main/resources/src/webapp/images/ajax-loader.gif create mode 100644 src/main/resources/src/webapp/index.html create mode 100644 src/main/resources/src/webapp/lazy.html create mode 100644 src/main/resources/src/webapp/parallel.html create mode 100644 src/main/resources/src/webapp/scripts/jquery.blockUI.js create mode 100644 src/main/resources/src/webapp/scripts/shBrushBash.js create mode 100644 src/main/resources/src/webapp/scripts/shBrushJava.js create mode 100644 src/main/resources/src/webapp/scripts/shBrushScala.js create mode 100644 src/main/resources/src/webapp/scripts/shBrushXml.js create mode 100644 src/main/resources/src/webapp/scripts/shCore.js create mode 100644 src/main/resources/src/webapp/security.html create mode 100644 src/main/resources/src/webapp/static/index.html create mode 100644 src/main/resources/src/webapp/templates-hidden/default.html create mode 100644 src/main/resources/src/webapp/templates-hidden/wizard-all.html create mode 100644 src/main/resources/src/webapp/templates.html create mode 100644 src/main/resources/src/webapp/wiring.html create mode 100644 src/main/resources/src/webapp/wizard.html create mode 100644 src/main/scala/net/liftweb/seventhings/lib/HelpersJBridge.scala create mode 100644 src/main/scala/net/liftweb/seventhings/snippet/MyWizardScala.scala diff --git a/project/build/LiftProject.scala b/project/build/LiftProject.scala new file mode 100644 index 0000000..b64da12 --- /dev/null +++ b/project/build/LiftProject.scala @@ -0,0 +1,26 @@ +import sbt._ + +class LiftProject(info: ProjectInfo) extends DefaultWebProject(info) { + val liftVersion = "2.3-SNAPSHOT" + + // uncomment the following if you want to use the snapshot repo + val scalatoolsSnapshot = ScalaToolsSnapshots + + // val localMaven = "local maven" at "file:///home/dpp/.m2/repository" + + // If you're using JRebel for Lift development, uncomment + // this line + // override def scanDirectories = Nil + + override def libraryDependencies = Set( + "net.liftweb" %% "lift-webkit" % liftVersion % "compile->default", + "net.liftweb" %% "lift-wizard" % liftVersion % "compile->default", + "org.mortbay.jetty" % "jetty" % "6.1.22" % "test->default", + "junit" % "junit" % "4.5" % "test->default", + "ch.qos.logback" % "logback-classic" % "0.9.26", + "org.scala-tools.testing" %% "specs" % "1.6.6" % "test->default", + "com.h2database" % "h2" % "1.2.138" + ) ++ super.libraryDependencies + + +} diff --git a/src/main/java/bootstrap/liftweb/Boot.java b/src/main/java/bootstrap/liftweb/Boot.java index 57c5b0d..fc879f8 100644 --- a/src/main/java/bootstrap/liftweb/Boot.java +++ b/src/main/java/bootstrap/liftweb/Boot.java @@ -2,6 +2,10 @@ import net.liftweb.http.*; +import net.liftweb.http.Html5Properties; +import net.liftweb.http.HtmlProperties; +import net.liftweb.http.LiftRulesJ; +import net.liftweb.http.Req; import net.liftweb.http.js.JsCmd; import net.liftweb.http.provider.HTTPRequest; import net.liftweb.sitemap.Menu; diff --git a/src/main/java/net/liftweb/seventhings/lib/HelpersJ.java b/src/main/java/net/liftweb/seventhings/lib/HelpersJ.java index c304f04..a788246 100644 --- a/src/main/java/net/liftweb/seventhings/lib/HelpersJ.java +++ b/src/main/java/net/liftweb/seventhings/lib/HelpersJ.java @@ -1,13 +1,11 @@ package net.liftweb.seventhings.lib; -import net.liftweb.util.Helpers; -import net.liftweb.util.Helpers$; public class HelpersJ { - private final static Helpers$ j = Helpers$.MODULE$; + private final static HelpersJBridge j = new HelpersJBridge(); - public final static Helpers$ j() { + public final static HelpersJBridge j() { return j; } diff --git a/src/main/java/net/liftweb/seventhings/lib/ListJ.java b/src/main/java/net/liftweb/seventhings/lib/ListJ.java index ac6791b..922d2ea 100644 --- a/src/main/java/net/liftweb/seventhings/lib/ListJ.java +++ b/src/main/java/net/liftweb/seventhings/lib/ListJ.java @@ -1,6 +1,7 @@ package net.liftweb.seventhings.lib; import scala.collection.Seq; +import scala.collection.mutable.ListBuffer; public class ListJ { @@ -8,4 +9,12 @@ public static Seq Nil() { return scala.collection.immutable.Nil$.MODULE$; } + public static Seq toSeq(Object... obj) { + ListBuffer buf = new ListBuffer(); + for (Object o : obj) { + buf.$plus$eq(o); + } + return buf.toSeq(); + } + } diff --git a/src/main/java/net/liftweb/seventhings/lib/Matcher.java b/src/main/java/net/liftweb/seventhings/lib/Matcher.java new file mode 100644 index 0000000..6185532 --- /dev/null +++ b/src/main/java/net/liftweb/seventhings/lib/Matcher.java @@ -0,0 +1,79 @@ +package net.liftweb.seventhings.lib; + +import scala.PartialFunction; + +import java.util.List; +import java.util.Collections; +import java.util.Arrays; + +interface MatchClause { + public boolean test (T subject); + public Object apply(T subject); +} + +interface F0V { //extends PartialFunction { + public Object apply(); +} + + +class Matcher { + + private final List> matchers; + + public static Matcher matcher(MatchClause... matchers) { + return new Matcher(matchers); + } + + public Matcher(MatchClause... matchers) { + this.matchers = Collections.unmodifiableList(Arrays.asList(matchers)); + } + + public F0V match(final T subject) { + return new F0V() { + public Object apply() { + for(MatchClause matcher: matchers) { + if(matcher.test(subject)) { + return matcher.apply(subject); + } + } + return null; // TODO should return Empty + } + }; + } + +} + +/* +class liftjmatch { + public static void main(String[] args) { + + final MatchClause mString = new MatchClause() { + public boolean test(Object x) { return x instanceof String; } + + public void apply(Object x) { System.out.println("String: " + x); } + }; + + final MatchClause mInteger = new MatchClause() { + public boolean test(Object x) { return x instanceof Integer; } + + public void apply(Object x) { System.out.println("Integer: " + x); } + }; + + final MatchClause mOther = new MatchClause() { + public boolean test(Object x) { return true; } + + public void apply(Object x) { System.out.println("Other: " + x); } + }; + + Matcher m = Matcher.matcher( + mString, + mInteger, + mOther + ); + + m.match("Hello World").apply(); + m.match(1).apply(); + } +} +*/ + diff --git a/src/main/java/net/liftweb/seventhings/snippet/LongTime.java b/src/main/java/net/liftweb/seventhings/snippet/LongTime.java index 0f092ae..dd93488 100644 --- a/src/main/java/net/liftweb/seventhings/snippet/LongTime.java +++ b/src/main/java/net/liftweb/seventhings/snippet/LongTime.java @@ -1,5 +1,7 @@ package net.liftweb.seventhings.snippet; +import net.liftweb.http.SHtmlJ; +import net.liftweb.seventhings.lib.HelpersJ; import net.liftweb.util.Css; import net.liftweb.util.Helpers; import scala.Function1; @@ -14,23 +16,14 @@ */ public class LongTime { - SecureRandom _random = new SecureRandom(); - - long randomLong(long mod) { - synchronized (_random) { - return Math.abs(_random.nextLong()) % mod; - } - } - public Function1 render() { // capture the start time - //Date start = HelpersJ.j().now(); - Date start = new Date(); + Date start = HelpersJ.j().now(); // sleep for up to 15 seconds try { - Thread.sleep(randomLong(15000)); + Thread.sleep(HelpersJ.j().randomLong(15000)); } catch (InterruptedException IGNORE) { } diff --git a/src/main/java/net/liftweb/seventhings/snippet/MyWizard.java b/src/main/java/net/liftweb/seventhings/snippet/MyWizard.java new file mode 100644 index 0000000..bf18b0d --- /dev/null +++ b/src/main/java/net/liftweb/seventhings/snippet/MyWizard.java @@ -0,0 +1,82 @@ +package net.liftweb.seventhings.snippet; + +import net.liftweb.http.AbstractScreen; +import net.liftweb.http.SJ; +import net.liftweb.http.js.JsCmd; +import net.liftweb.http.js.jquery.JqJsCmds; +import net.liftweb.seventhings.lib.JqJsCmdsJ; +import net.liftweb.seventhings.lib.ListJ; +import net.liftweb.seventhings.lib.WizardJ; +import net.liftweb.util.Func; +import net.liftweb.util.Func0; +import net.liftweb.wizard.Wizard; + +/** + * An example of a wizard in Lift + */ +public class MyWizard extends WizardJ { + + private MyWizardScala wizardScala = new MyWizardScala(); + + private final MyWizardScala.ParentNameScreen parentName; + private final MyWizardScala.FavoritePetScreen favoritePet; + private final MyWizardScala.NameAndAgeScreen nameAndAge; + + public MyWizard() { + parentName = wizardScala.getParentName(); + favoritePet = wizardScala.getFavoritePet(); + nameAndAge = wizardScala.getNameAndAge(); + } + + public JsCmd calcAjaxOnDone() { + return JqJsCmdsJ.j().unblock(); + } + + // define the first screen + + // We ask the parent's name if the person is under 18 +// private WizardJ.ScreenJ parentNameObj = new WizardJ.ScreenJ() { +// String parentName = fieldj(SJ.j().$qmark("Mom or Dad's name"), ListJ.toSeq( +// valMinLen(Func.lift(new Func0() { +// public Integer apply() { +// return 2; +// } +// }), Func.lift(new Func0() { +// public String apply() { +// return SJ.j().$qmark("Name Too Short"); +// } +// })), +// valMaxLen(Func.lift(new Func0() { +// public Integer apply() { +// return 40; +// } +// }), Func.lift(new Func0() { +// public String apply() { +// return SJ.j().$qmark("Name Too Long"); +// } +// })))); +// }; + + + // we ask for the favorite pet +// private WizardJ.Screen favoritePet = new WizardJ.Screen() { +// String petName = AbstractScreen.field(SJ.j().$qmark("Pet's name", "", +// AbstractScreen.valMinLen(2, SJ.j().$qmark("Name Too Short")), +// AbstractScreen.valMaxLen(40, SJ.j().$qmark("Name Too Long")))); +// }; + + + + +// // what to do on completion of the wizard +// public void finish() { +// SJ.j().notice("Thank you for registering your pet: " + +// favoritePet.petName() + +// " your age * 3: " + nameAndAge.age() * 3); +// } + + public void finish() { + wizardScala.finish(); + } + +} diff --git a/src/main/java/net/liftweb/seventhings/snippet/MyWizardJava.java b/src/main/java/net/liftweb/seventhings/snippet/MyWizardJava.java deleted file mode 100644 index e9d89b3..0000000 --- a/src/main/java/net/liftweb/seventhings/snippet/MyWizardJava.java +++ /dev/null @@ -1,66 +0,0 @@ -package net.liftweb.seventhings.snippet; - -import net.liftweb.http.AbstractScreen; -import net.liftweb.http.SJ; -import net.liftweb.http.js.JsCmd; -import net.liftweb.http.js.jquery.JqJsCmds; -import net.liftweb.seventhings.lib.JqJsCmdsJ; -import net.liftweb.seventhings.lib.WizardJ; -import net.liftweb.util.Func; -import net.liftweb.util.Func0; -import net.liftweb.wizard.Wizard; - -/** - * An example of a wizard in Lift - */ -public class MyWizardJava extends WizardJ { - - public JsCmd calcAjaxOnDone() { - return JqJsCmdsJ.j().unblock(); - } - - // define the first screen - - // We ask the parent's name if the person is under 18 - private WizardJ.ScreenJ parentNameObj = new WizardJ.ScreenJ() { - String parentName = field(SJ.j().$qmark("Mom or Dad's name"), "", - valMinLen(Func.lift(new Func0() { - public Integer apply() { - return 2; - } - }), Func.lift(new Func0(){ - public String apply() { - return SJ.j().$qmark("Name Too Short"); - } - })), - valMaxLen(Func.lift(new Func0(){ - public Integer apply() { - return 40; - } - }), Func.lift(new Func0(){ - public String apply() { - return SJ.j().$qmark("Name Too Long"); - } - }))); - }; - - - // we ask for the favorite pet -// private WizardJ.Screen favoritePet = new WizardJ.Screen() { -// String petName = AbstractScreen.field(SJ.j().$qmark("Pet's name", "", -// AbstractScreen.valMinLen(2, SJ.j().$qmark("Name Too Short")), -// AbstractScreen.valMaxLen(40, SJ.j().$qmark("Name Too Long")))); -// }; - - - - - // what to do on completion of the wizard - public void finish() { - SJ.j().notice("Thank you for registering your pet: "); // + -// favoritePet.petName + -// " your age * 3: " + nameAndAge.age * 3); - } - - -} diff --git a/src/main/resources/src/java/bootstrap/liftweb/Boot.java b/src/main/resources/src/java/bootstrap/liftweb/Boot.java new file mode 100644 index 0000000..fc879f8 --- /dev/null +++ b/src/main/resources/src/java/bootstrap/liftweb/Boot.java @@ -0,0 +1,100 @@ +package bootstrap.liftweb; + + +import net.liftweb.http.*; +import net.liftweb.http.Html5Properties; +import net.liftweb.http.HtmlProperties; +import net.liftweb.http.LiftRulesJ; +import net.liftweb.http.Req; +import net.liftweb.http.js.JsCmd; +import net.liftweb.http.provider.HTTPRequest; +import net.liftweb.sitemap.Menu; +import net.liftweb.sitemap.MenuJ; +import net.liftweb.sitemap.SiteMap; +import net.liftweb.sitemap.SiteMapJ; +import net.liftweb.util.Func; +import net.liftweb.util.Func0; +import net.liftweb.util.Func1; + +/** + * A class that's instantiated early and run. It allows the application + * to modify lift's environment + */ +public class Boot { + SiteMap makeSiteMap() { + return SiteMapJ.build( + MenuJ.j().i("Home").path("index"), + MenuJ.j().i("Lazy Loading").path("lazy"), + MenuJ.j().i("Parallel Rendering").path("parallel"), + MenuJ.j().i("Comet & Ajax").path("comet"), + MenuJ.j().i("Wiring").path("wiring"), + MenuJ.j().i("Designer Friendly Templates").path("templates"), + MenuJ.j().i("Wizard").path("wizard"), + MenuJ.j().i("Security").path("security")); + + /* + * FIXME -- We need Menu.apply() equiv in Java for: + Menu("lazy", "Lazy Loading") / "lazy", + Menu("parallel", "Parallel Rendering") / "parallel", + Menu("comet", "Comet & Ajax") / "comet", + Menu("wiring", "Wiring") / "wiring", + Menu("templates", "Designer Friendly Templates") / "templates", + Menu("wizard", "Wizard") / "wizard", + Menu("security", "Security") / "security") + */ + } + + + public void boot() { + // where to search snippet + LiftRulesJ.j().addToPackages("net.liftweb.seventhings"); + + // Set the sitemap + LiftRulesJ.j().setSiteMapFunc(Func.lift(new Func0() { + public SiteMap apply() { + return makeSiteMap(); + } + })); + + + //Show the spinny image when an Ajax call starts + LiftRulesJ.j(). + setAjaxStart(new Func0() { + public JsCmd apply() { + return LiftRulesJ.j(). + jsArtifacts().show("ajax-loader").cmd(); + } + }); + + // Make the spinny image go away when it ends + LiftRulesJ.j(). + setAjaxEnd(new Func0() { + public JsCmd apply() { + return LiftRulesJ.j(). + jsArtifacts().hide("ajax-loader").cmd(); + } + }); + + // Force the request to be UTF-8 + LiftRulesJ. + j(). + early().append(Func.lift(new Func1() { + public Object apply(HTTPRequest req) { + req.setCharacterEncoding("UTF-8"); + return ""; + } + })); + + + // Use HTML5 for rendering + LiftRulesJ.j(). + htmlProperties(). + theDefault(). + set(Func.vendor(Func.lift(new Func1() { + public HtmlProperties apply(Req r) { + return new Html5Properties(r.userAgent()); + } + }))); + + } +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/comet/Chat.java b/src/main/resources/src/java/net/liftweb/seventhings/comet/Chat.java new file mode 100644 index 0000000..7870011 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/comet/Chat.java @@ -0,0 +1,34 @@ +package net.liftweb.seventhings.comet; + +import net.liftweb.common.SimpleActor; +import net.liftweb.common.SimpleVector; +import net.liftweb.http.CometActorJWithCometListener; +import net.liftweb.http.RenderOut; +import net.liftweb.util.ClearClearable; +import net.liftweb.util.SeqStringIterableConst; + +/** + * The Comet (server push) Chat component + */ +public class Chat extends CometActorJWithCometListener { + // private state + private SimpleVector msgs = new SimpleVector(); // private state + + // register this component + public SimpleActor registerWith() { + return ChatServer.j(); + } + + // handle an incoming message containing a List + @Receive public void messages(SimpleVector updatedMessages) { + msgs = updatedMessages; + reRender(); + } + + // render the component + public RenderOut render() { + return nsToNsFuncToRenderOut(new ClearClearable(). + sel("li *", new SeqStringIterableConst(msgs))); + } + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/comet/ChatServer.java b/src/main/resources/src/java/net/liftweb/seventhings/comet/ChatServer.java new file mode 100644 index 0000000..52c5fdf --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/comet/ChatServer.java @@ -0,0 +1,51 @@ +package net.liftweb.seventhings.comet; + +import net.liftweb.common.SimpleVector; +import net.liftweb.http.LiftActorJWithListenerManager; + +/** + * The chat server + */ +public class ChatServer extends LiftActorJWithListenerManager { + + private static ChatServer INSTANCE = null; + + // private state. The messages + private SimpleVector msgs = new SimpleVector(); // the private data + + private ChatServer() { + msgs = msgs.append("Welcome"); + } + + public synchronized static ChatServer j() { + if (INSTANCE == null) { + INSTANCE = new ChatServer(); + } + return INSTANCE; + } + + @Receive + /** + * A String is sent as a message to this Actor. Process it + */ + private void gotAString(String s) { + // add to the messages. No need to synchronize because + // the method will only be invoked by the Actor thread and + // only one message will be processed at once + msgs = msgs.append(s).takeRight(20); + + // update the listeners + updateListeners(); + } + + // what we send to listeners on update + public Object createUpdate() { + // make a copy of the list and send it to the listeners as unmodifable + // Note, if we used Scala's immutable collections or even Functional + // Java's immutable List, we would not have to make a defensive copy + // of the messages + return msgs; + } +} + + diff --git a/src/main/resources/src/java/net/liftweb/seventhings/comet/Yacker.java b/src/main/resources/src/java/net/liftweb/seventhings/comet/Yacker.java new file mode 100644 index 0000000..ef32a1f --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/comet/Yacker.java @@ -0,0 +1,35 @@ +package net.liftweb.seventhings.comet; + +import net.liftweb.common.SimpleActor; +import net.liftweb.http.CometActorJ; +import net.liftweb.http.RenderOut; +import net.liftweb.util.*; +import net.liftweb.http.*; +import net.liftweb.util.Css; +import net.liftweb.util.ScheduleJBridge; + +import java.util.Date; + +public class Yacker extends CometActorJ { +// public void localSetup() { +// ping(); +// super.localSetup(); +// } + + private void ping() { + new ScheduleJBridge().schedule().perform((SimpleActor) this, new Pinger(), 10000); + } + + @Receive + protected void ping(Pinger p) { + ping(); + super.reRender(); + } + + public RenderOut render() { + return nsToNsFuncToRenderOut(Css.sel("#yack", new Date().toString())); + } + + class Pinger { + } +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/lib/BoxJ.java b/src/main/resources/src/java/net/liftweb/seventhings/lib/BoxJ.java new file mode 100644 index 0000000..c492b31 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/lib/BoxJ.java @@ -0,0 +1,11 @@ +package net.liftweb.seventhings.lib; + +public class BoxJ { + + private final static BoxJBridge j = new BoxJBridge(); + + public static BoxJBridge j() { + return j; + } + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/lib/HelpersJ.java b/src/main/resources/src/java/net/liftweb/seventhings/lib/HelpersJ.java new file mode 100644 index 0000000..a788246 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/lib/HelpersJ.java @@ -0,0 +1,12 @@ +package net.liftweb.seventhings.lib; + + +public class HelpersJ { + + private final static HelpersJBridge j = new HelpersJBridge(); + + public final static HelpersJBridge j() { + return j; + } + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/lib/JqJsCmdsJ.java b/src/main/resources/src/java/net/liftweb/seventhings/lib/JqJsCmdsJ.java new file mode 100644 index 0000000..58e8ca1 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/lib/JqJsCmdsJ.java @@ -0,0 +1,21 @@ +package net.liftweb.seventhings.lib; + +import net.liftweb.http.js.JE; +import net.liftweb.http.js.JsCmd; +import net.liftweb.http.js.jquery.JqJE; +import net.liftweb.http.js.jquery.JqJsCmds; +import scala.xml.NodeSeq; + +public class JqJsCmdsJ { + + private final static JqJsCmdsJBridge j = new JqJsCmdsJBridge(); + + public static JsCmd appendHtml(String uid, NodeSeq content) { + return (new JqJE.JqId(new JE.Str(uid)).$tilde$greater(new JqJE.JqAppend(content))).cmd(); + } + + public static JqJsCmdsJBridge j() { + return j; + } + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/lib/ListJ.java b/src/main/resources/src/java/net/liftweb/seventhings/lib/ListJ.java new file mode 100644 index 0000000..922d2ea --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/lib/ListJ.java @@ -0,0 +1,20 @@ +package net.liftweb.seventhings.lib; + +import scala.collection.Seq; +import scala.collection.mutable.ListBuffer; + +public class ListJ { + + public static Seq Nil() { + return scala.collection.immutable.Nil$.MODULE$; + } + + public static Seq toSeq(Object... obj) { + ListBuffer buf = new ListBuffer(); + for (Object o : obj) { + buf.$plus$eq(o); + } + return buf.toSeq(); + } + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/lib/Matcher.java b/src/main/resources/src/java/net/liftweb/seventhings/lib/Matcher.java new file mode 100644 index 0000000..6185532 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/lib/Matcher.java @@ -0,0 +1,79 @@ +package net.liftweb.seventhings.lib; + +import scala.PartialFunction; + +import java.util.List; +import java.util.Collections; +import java.util.Arrays; + +interface MatchClause { + public boolean test (T subject); + public Object apply(T subject); +} + +interface F0V { //extends PartialFunction { + public Object apply(); +} + + +class Matcher { + + private final List> matchers; + + public static Matcher matcher(MatchClause... matchers) { + return new Matcher(matchers); + } + + public Matcher(MatchClause... matchers) { + this.matchers = Collections.unmodifiableList(Arrays.asList(matchers)); + } + + public F0V match(final T subject) { + return new F0V() { + public Object apply() { + for(MatchClause matcher: matchers) { + if(matcher.test(subject)) { + return matcher.apply(subject); + } + } + return null; // TODO should return Empty + } + }; + } + +} + +/* +class liftjmatch { + public static void main(String[] args) { + + final MatchClause mString = new MatchClause() { + public boolean test(Object x) { return x instanceof String; } + + public void apply(Object x) { System.out.println("String: " + x); } + }; + + final MatchClause mInteger = new MatchClause() { + public boolean test(Object x) { return x instanceof Integer; } + + public void apply(Object x) { System.out.println("Integer: " + x); } + }; + + final MatchClause mOther = new MatchClause() { + public boolean test(Object x) { return true; } + + public void apply(Object x) { System.out.println("Other: " + x); } + }; + + Matcher m = Matcher.matcher( + mString, + mInteger, + mOther + ); + + m.match("Hello World").apply(); + m.match(1).apply(); + } +} +*/ + diff --git a/src/main/resources/src/java/net/liftweb/seventhings/lib/TopScopeJ.java b/src/main/resources/src/java/net/liftweb/seventhings/lib/TopScopeJ.java new file mode 100644 index 0000000..67ef807 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/lib/TopScopeJ.java @@ -0,0 +1,13 @@ +package net.liftweb.seventhings.lib; + +import scala.xml.NamespaceBinding; + +public class TopScopeJ { + + private static final NamespaceBinding j = new XmlJBridge().topScope(); + + public static NamespaceBinding j() { + return j; + } + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/lib/WiringUIJ.java b/src/main/resources/src/java/net/liftweb/seventhings/lib/WiringUIJ.java new file mode 100644 index 0000000..5ef0b0c --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/lib/WiringUIJ.java @@ -0,0 +1,15 @@ +package net.liftweb.seventhings.lib; + +import net.liftweb.http.WiringUI; + +public class WiringUIJ { + + private static final Object j = new WiringUIBridge().wiringUI(); + + public static Object j() { + return j; + } + + + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/lib/XmlJ.java b/src/main/resources/src/java/net/liftweb/seventhings/lib/XmlJ.java new file mode 100644 index 0000000..57682b3 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/lib/XmlJ.java @@ -0,0 +1,66 @@ +package net.liftweb.seventhings.lib; + +import scala.collection.mutable.ListBuffer; +import scala.xml.MetaData; +import scala.xml.NamespaceBinding; +import scala.xml.NodeSeq; + +public class XmlJ { + private static final XmlJBridge bridge = new XmlJBridge(); + + private static final NamespaceBinding topScope = bridge.topScope(); + private static final MetaData xmlNull = bridge.getNull(); + + public static NamespaceBinding topScope() { + return topScope; + } + + public static MetaData xmlNull() { + return xmlNull; + } + + public static NodeSeq elemSeq(scala.xml.Node... nodes) { + ListBuffer buf = new ListBuffer(); + + for (scala.xml.Node n : nodes) { + buf.$plus$eq(n); + } + NodeSeq seq1 = scala.xml.NodeSeq.seqToNodeSeq(buf); + return seq1; + } + + public static scala.xml.Elem elem(String label, MetaData attributes, scala.xml.Node... children) { + scala.xml.Elem el = new scala.xml.Elem(null, label, attributes, topScope(), elemSeq(children)); + return el; + } + + public static scala.xml.Elem elem(String label, scala.xml.Node... children) { + scala.xml.Elem el = new scala.xml.Elem(null, label, xmlNull(), topScope(), elemSeq(children)); + return el; + } + + public static scala.xml.Elem nselem(String prefix, String label, MetaData attributes, scala.xml.Node... children) { + scala.xml.Elem el = new scala.xml.Elem(prefix, label, attributes, topScope(), elemSeq(children)); + return el; + } + + public static scala.xml.Elem nselem(String prefix, String label, scala.xml.Node... children) { + scala.xml.Elem el = new scala.xml.Elem(prefix, label, xmlNull(), topScope(), elemSeq(children)); + return el; + } + + public static MetaData attr(String key, String value) { + return new scala.xml.UnprefixedAttribute(key, new scala.xml.Text(value), xmlNull()); + } + + public static scala.xml.Node text(String text) { + return new scala.xml.Text(text); + } + + public static NodeSeq toNodeSeq(scala.xml.Elem el) { + return scala.xml.NodeSeq.fromSeq(el.theSeq()); + } + + + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/lib/XmlNullJ.java b/src/main/resources/src/java/net/liftweb/seventhings/lib/XmlNullJ.java new file mode 100644 index 0000000..4aa3954 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/lib/XmlNullJ.java @@ -0,0 +1,22 @@ +package net.liftweb.seventhings.lib; + +import com.sun.istack.internal.Nullable; +import scala.xml.MetaData; +import scala.xml.Null; + +/** + * This source file belongs to the AGYNAMIX GUI AppFramework. + * User: tuhlmann + * Date: 11.02.11 + * Time: 10:58 + * (c) AGYNAMIX Torsten Uhlmann + */ +public class XmlNullJ { + + private static final MetaData j = new XmlNullJBridge().getNull(); + + public static MetaData j() { + return j; + } + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/snippet/AjaxRunner.java b/src/main/resources/src/java/net/liftweb/seventhings/snippet/AjaxRunner.java new file mode 100644 index 0000000..14b6417 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/snippet/AjaxRunner.java @@ -0,0 +1,31 @@ +package net.liftweb.seventhings.snippet; + +import net.liftweb.common.Box; +import net.liftweb.common.Empty; +import net.liftweb.http.SHtmlJ; +import net.liftweb.http.js.JsCmd; +import net.liftweb.http.js.JsExp; +import net.liftweb.http.js.jquery.JqJsCmds; +import net.liftweb.seventhings.lib.BoxJ; +import net.liftweb.seventhings.lib.JqJsCmdsJ; +import net.liftweb.util.Css; +import scala.Function1; +import scala.xml.Elem; +import scala.xml.NodeSeq; +import static net.liftweb.seventhings.lib.XmlJ.*; + +public class AjaxRunner { + + public Function1 render() { + + final scala.Tuple2 ajax = SHtmlJ.j().ajaxInvoke(net.liftweb.util.Func.lift(new net.liftweb.util.Func0() { + public JsCmd apply() { + final Elem el = elem("div", nselem("lift", "MyWizard", attr("ajax", "true"))); + return new JqJsCmds.ModalDialog(toNodeSeq(el), (Box)BoxJ.j().empty()); + } + })); + + return Css.sel("* [onclick]", ((JsExp)ajax._2()).toJsCmd()); + } + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/snippet/ChatIn.java b/src/main/resources/src/java/net/liftweb/seventhings/snippet/ChatIn.java new file mode 100644 index 0000000..62f42cc --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/snippet/ChatIn.java @@ -0,0 +1,49 @@ +package net.liftweb.seventhings.snippet; + + +import net.liftweb.http.SHtmlJ; +import net.liftweb.http.SessionVar; +import net.liftweb.http.VarsJ; +import net.liftweb.http.js.JE; +import net.liftweb.http.js.JsCmds; +import net.liftweb.seventhings.comet.ChatServer; +import net.liftweb.util.Func; +import net.liftweb.util.Func1; +import scala.Function1; +import scala.xml.NodeSeq; + +/** + * The ChatIn snippet + */ +public class ChatIn { + // max count per session + static final SessionVar lineCnt = VarsJ.vendSessionVar(0); + + // return the code that transforms the template input to + // the dynamic output + public Function1 render() { + + // associate a function with the submission of the form element + return SHtmlJ.j().onSubmit(Func.lift(new Func1() { + public Object apply(String s) { + // get the session-specific line count + int lineCntIs = lineCnt.is(); + + // if the message is small enough and the session + // hasn't sent too many messages, send the String to the ChatServer + if (s.length() < 50 && lineCntIs < 20) { + ChatServer.j().send(s); + + // update the line count + lineCnt.set(lineCntIs + 1); + } + + // clear the browser's input box + return new JsCmds.SetValById("chat_in", new JE.Str("")); // clear the input box + } + } + )); + } + + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/snippet/FetchAd.java b/src/main/resources/src/java/net/liftweb/seventhings/snippet/FetchAd.java new file mode 100644 index 0000000..1003942 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/snippet/FetchAd.java @@ -0,0 +1,25 @@ +package net.liftweb.seventhings.snippet; + +import net.liftweb.util.Css; +import scala.Function1; +import scala.xml.NodeSeq; + +public class FetchAd { + + /** return the code that transforms the template input to + the dynamic output + */ + public Function1 render() { + + // sleep for 1/2 second + try { + Thread.sleep(500); + } catch (InterruptedException IGNORE) {} + + // send the result back + return Css.sel(".ad", Thread.currentThread().getName()); + + } + + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/snippet/InvoiceWiring.java b/src/main/resources/src/java/net/liftweb/seventhings/snippet/InvoiceWiring.java new file mode 100644 index 0000000..30f149c --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/snippet/InvoiceWiring.java @@ -0,0 +1,303 @@ +package net.liftweb.seventhings.snippet; + +import net.liftweb.http.SHtml; +import net.liftweb.http.SHtmlJ; +import net.liftweb.http.WiringUI; +import net.liftweb.http.js.JsCmd; +import net.liftweb.http.js.JsCmds; +import net.liftweb.http.js.JsExp; +import net.liftweb.http.js.jquery.JqJsCmds; +import net.liftweb.http.js.jquery.JqWiringSupport; +import net.liftweb.seventhings.lib.*; +import net.liftweb.util.*; +import net.liftweb.util.Css; +import net.liftweb.util.Func; +import net.liftweb.util.Func0; +import net.liftweb.util.Func1; +import net.liftweb.util.Func2; +import scala.Function1; +import scala.Function2; +import scala.collection.Iterator; +import scala.collection.immutable.Nil; +import scala.collection.mutable.ListBuffer; +import scala.runtime.AbstractFunction1; +import scala.runtime.AbstractFunction2; +import scala.xml.Elem; +import scala.xml.NodeSeq; +import scala.xml.Text; +import scala.collection.JavaConversions; + +import javax.swing.text.Element; +import java.text.NumberFormat; +import java.util.ArrayList; + +import static net.liftweb.seventhings.lib.XmlJ.*; + +/** + * An invoice system with subtotals, tax, etc. + */ +public class InvoiceWiring { + + final Info info; + + class Line { + public final String guid; + public final String name; + public final double price; + public final boolean taxable; + + Line(String guid, String name, double price, boolean taxable) { + this.guid = guid; + this.name = name; + this.price = price; + this.taxable = taxable; + } + } + + /** + * Define the relationships among the items + */ + private class Info { + + final InvoiceWiring iWiring; + + final net.liftweb.util.ValueCell invoices; + final net.liftweb.util.ValueCell taxRate; + final net.liftweb.util.Cell subtotal; + final net.liftweb.util.Cell taxable; + final net.liftweb.util.Cell tax; + final net.liftweb.util.Cell total; + + Info(InvoiceWiring iWiring) { + this.iWiring = iWiring; + ListBuffer buf = new ListBuffer(); + buf.$plus$eq(iWiring.newLine()); + invoices = new net.liftweb.util.ValueCell(buf.toList()); + taxRate = new net.liftweb.util.ValueCell(0.05d); + + subtotal = invoices.lift(Func.lift(new Func1, Double>(){ + public Double apply(scala.collection.immutable.List in) { + return in.foldLeft(0d, Func.lift(new Func2(){ + public Double apply(Double in, Line line) { + return in + line.price; + } + })); + } + })); + + taxable = invoices.lift(new AbstractFunction1, Double>(){ + public Double apply(scala.collection.immutable.List in) { + return in.foldLeft(0d, new AbstractFunction2(){ + public Double apply(Double in, Line line) { + if (line.taxable) { + return in + line.price; + } else { + return in; + } + } + }); + } + }); + + tax = taxRate.lift(taxable, Func.lift(new Func2(){ + public Double apply(Double left, Double right) { + return left * right; + } + })); + + total = subtotal.lift(tax, Func.lift(new Func2(){ + public Double apply(Double left, Double right) { + return left + right; + } + })); + } + + } + + public InvoiceWiring() { + this.info = new Info(this); + } + + /** + * wire an element to subtotal + */ + public Function1 subtotal() { + return WiringUI.toNode(info.subtotal, doubleDraw()); + } + + /** + * Wire an element to taxable + */ + public Function1 taxable() { + return WiringUI.toNode(info.taxable, doubleDraw()); + } + + public Function1 tax() { + return WiringUI.toNode(info.tax, JqWiringSupport.fade(), doubleDraw()); + } + + public Function1 total() { + return WiringUI.toNode(info.total, JqWiringSupport.fade(), doubleDraw()); + } + + /** * + * The tax rate input + * def ajaxText(value: String, func: String => JsCmd, attrs: ElemAttr*): Elem + */ + public Elem taxRate() { + return SHtmlJ.j().ajaxText(info.taxRate.get().toString(), + doubleToJsCmd(Func.lift(new Func1() { + public Object apply(Double d) { + return info.taxRate.set(d); + } + })), ListJ.Nil()); + } + + /** + * Add a line to the input + */ + public Function1 addLine() { + final scala.Tuple2 ajax = SHtmlJ.j().ajaxInvoke(net.liftweb.util.Func.lift(new net.liftweb.util.Func0() { + public JsCmd apply() { + return JqJsCmdsJ.appendHtml("invoice_lines", renderLine(appendLine())); + } + })); + + return Css.sel("* [onclick]", ((JsExp)ajax._2()).toJsCmd()); + } + + /** + * Draw all the input lines + */ + public Function1 showLines() { + return Css.sel("* *", renderLines((scala.collection.immutable.List)info.invoices.get())); + } + + private NodeSeq renderLines(scala.collection.immutable.List lines) { + ListBuffer buf = new ListBuffer(); + if (lines != null){ + for (Iterator it = lines.toIterator(); it.hasNext();) { + final Line l = (Line) it.next(); // or is it a Box? + buf.$plus$eq(renderLineAsElem(l)); + } + } + return scala.xml.NodeSeq.fromSeq(buf.toSeq()); + } + + public NodeSeq renderLine(final Line theLine) { + return toNodeSeq(renderLineAsElem(theLine)); + } + + /** + * render a line of input fields + */ + private Elem renderLineAsElem(final Line theLine) { + + if (theLine == null) { + return elem("div", text("the Line is NULL")); + } + + System.out.println("renderLineAsElem"); + + Elem el = elem("div", attr("id", theLine.guid), + + SHtmlJ.j().ajaxText(theLine.name, Func.lift(new Func1() { + public JsCmd apply(final String s) { + System.out.println("JsCmd APPLY. s="+s); + return mutateLine(theLine.guid, new Func1() { + public Line apply(Line in) { + System.out.println("mutateLine Func. Line="+in); + Line out = new Line(in.guid, s, in.price, in.taxable); + System.out.println("mutateLine Func. Line Out="+out); + return out; + } + }); + } + }), ListJ.Nil()), + + SHtmlJ.j().ajaxText(""+theLine.price, Func.lift(new Func1() { + public JsCmd apply(final String s) { + final double dbl = Double.parseDouble(s); + return mutateLine(theLine.guid, new Func1() { + public Line apply(Line in) { + return new Line(in.guid, in.name, dbl, in.taxable); + } + }); + } + }), ListJ.Nil()), + + SHtmlJ.j().ajaxCheckbox(theLine.taxable, Func.lift(new Func1() { + @Override + public JsCmd apply(final Boolean b) { + return mutateLine(theLine.guid, new Func1(){ + public Line apply(Line in) { + return new Line(in.guid, in.name, in.price, b); + } + }); + } + }), ListJ.Nil())); + + return el; + + } + + private Line appendLine() { + Line ret = newLine(); + scala.collection.immutable.List l = (scala.collection.immutable.List) info.invoices.get(); + l.$colon$colon(ret); + info.invoices.set(l); + return ret; + } + + + public Line newLine() { + return new Line(HelpersJ.j().nextFuncName(), "", 0, false); + } + + /** + * Mutate a line and update the Info field + */ + private JsCmd mutateLine(final String guid, final Func1 fIn) { + final Function1 f = Func.lift(fIn); + scala.collection.immutable.List all = (scala.collection.immutable.List) info.invoices.get(); + + java.util.List head = new java.util.ArrayList(); + java.util.List rest = new java.util.ArrayList(); + for (Object o : JavaConversions.asJavaIterable(all)) { + Line l = (Line) o; + if (l.guid.equals(guid)) { + head.add((Line)f.apply(l)); + } else { + rest.add(l); + } + } + + head.addAll(rest); + + info.invoices.set(JavaConversions.asScalaBuffer(head).toList()); + return JsCmds.Noop(); + } + + private Function2 doubleDraw() { + return Func.lift(new net.liftweb.util.Func2() { + public NodeSeq apply(Double d, NodeSeq ns) { + return new Text(NumberFormat.getCurrencyInstance().format(d)); + } + }); + } + + + private Function1 doubleToJsCmd(final Function1 in) { + return Func.lift(new Func1() { + public JsCmd apply(String str) { + try { + double d = Double.parseDouble(str); + return (JsCmd) in.apply(d); + } catch (Exception IGNORE) { + return JsCmds.Noop(); + } + } + }) ; + } + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/snippet/LongTime.java b/src/main/resources/src/java/net/liftweb/seventhings/snippet/LongTime.java new file mode 100644 index 0000000..dd93488 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/snippet/LongTime.java @@ -0,0 +1,35 @@ +package net.liftweb.seventhings.snippet; + +import net.liftweb.http.SHtmlJ; +import net.liftweb.seventhings.lib.HelpersJ; +import net.liftweb.util.Css; +import net.liftweb.util.Helpers; +import scala.Function1; +import scala.xml.NodeSeq; + +import java.security.SecureRandom; +import java.util.Date; +import java.util.Random; + +/** + * Do something that takes a long time to do + */ +public class LongTime { + + public Function1 render() { + + // capture the start time + Date start = HelpersJ.j().now(); + + // sleep for up to 15 seconds + try { + Thread.sleep(HelpersJ.j().randomLong(15000)); + } catch (InterruptedException IGNORE) { + } + + // send the result back + return Css.sel("#start", start.toString()).and(Css.sel("#end", new Date().toString())); + } + + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/snippet/MyWizard.java b/src/main/resources/src/java/net/liftweb/seventhings/snippet/MyWizard.java new file mode 100644 index 0000000..bf18b0d --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/snippet/MyWizard.java @@ -0,0 +1,82 @@ +package net.liftweb.seventhings.snippet; + +import net.liftweb.http.AbstractScreen; +import net.liftweb.http.SJ; +import net.liftweb.http.js.JsCmd; +import net.liftweb.http.js.jquery.JqJsCmds; +import net.liftweb.seventhings.lib.JqJsCmdsJ; +import net.liftweb.seventhings.lib.ListJ; +import net.liftweb.seventhings.lib.WizardJ; +import net.liftweb.util.Func; +import net.liftweb.util.Func0; +import net.liftweb.wizard.Wizard; + +/** + * An example of a wizard in Lift + */ +public class MyWizard extends WizardJ { + + private MyWizardScala wizardScala = new MyWizardScala(); + + private final MyWizardScala.ParentNameScreen parentName; + private final MyWizardScala.FavoritePetScreen favoritePet; + private final MyWizardScala.NameAndAgeScreen nameAndAge; + + public MyWizard() { + parentName = wizardScala.getParentName(); + favoritePet = wizardScala.getFavoritePet(); + nameAndAge = wizardScala.getNameAndAge(); + } + + public JsCmd calcAjaxOnDone() { + return JqJsCmdsJ.j().unblock(); + } + + // define the first screen + + // We ask the parent's name if the person is under 18 +// private WizardJ.ScreenJ parentNameObj = new WizardJ.ScreenJ() { +// String parentName = fieldj(SJ.j().$qmark("Mom or Dad's name"), ListJ.toSeq( +// valMinLen(Func.lift(new Func0() { +// public Integer apply() { +// return 2; +// } +// }), Func.lift(new Func0() { +// public String apply() { +// return SJ.j().$qmark("Name Too Short"); +// } +// })), +// valMaxLen(Func.lift(new Func0() { +// public Integer apply() { +// return 40; +// } +// }), Func.lift(new Func0() { +// public String apply() { +// return SJ.j().$qmark("Name Too Long"); +// } +// })))); +// }; + + + // we ask for the favorite pet +// private WizardJ.Screen favoritePet = new WizardJ.Screen() { +// String petName = AbstractScreen.field(SJ.j().$qmark("Pet's name", "", +// AbstractScreen.valMinLen(2, SJ.j().$qmark("Name Too Short")), +// AbstractScreen.valMaxLen(40, SJ.j().$qmark("Name Too Long")))); +// }; + + + + +// // what to do on completion of the wizard +// public void finish() { +// SJ.j().notice("Thank you for registering your pet: " + +// favoritePet.petName() + +// " your age * 3: " + nameAndAge.age() * 3); +// } + + public void finish() { + wizardScala.finish(); + } + +} diff --git a/src/main/resources/src/java/net/liftweb/seventhings/snippet/ShowCode.java b/src/main/resources/src/java/net/liftweb/seventhings/snippet/ShowCode.java new file mode 100644 index 0000000..639ae09 --- /dev/null +++ b/src/main/resources/src/java/net/liftweb/seventhings/snippet/ShowCode.java @@ -0,0 +1,146 @@ +package net.liftweb.seventhings.snippet; + + +import net.liftweb.common.Box; +import net.liftweb.http.LiftRulesJ; +import net.liftweb.http.SJ; +import scala.Option; +import scala.xml.Elem; +import scala.xml.NodeSeq; +import scala.xml.Text; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +import static net.liftweb.seventhings.lib.XmlJ.*; + +public class ShowCode { + + private String calcBrush(String fileName) { + if (fileName.endsWith(".html") || fileName.endsWith(".xml")) { + return "html"; + } + + if (fileName.endsWith(".java")) { + return "java"; + } + + return "scala"; + } + + private String gitDir(String fileName) { + if (fileName.endsWith(".html") || fileName.endsWith(".xml")) { + return "webapp"; + } + + if (fileName.endsWith(".java")) { + return "java"; + } + + return "scala"; + } + + + public NodeSeq render() { + + String codeListing = ""; + + Option fileNameO = SJ.j().attrsFlattenToMap().get("name"); + if (fileNameO.isDefined()) { + + String fileName = fileNameO.get(); + +// System.out.println("fileName="+fileName); + + // does not work with .or(LiftRulesJ.j().loadResource("/src/webapp"+fileName)) + Box codeBox = (LiftRulesJ.j().loadResource("/src/java"+fileName)).failMsg("Cannot find "+fileName); + + if (!codeBox.isDefined()) { + codeBox = (LiftRulesJ.j().loadResource("/src/webapp"+fileName)).failMsg("Cannot find "+fileName); + } + + if (codeBox.isDefined()) { + + byte[] code = codeBox.openTheBox(); + + Option startO = SJ.j().attrsFlattenToMap().get("start"); + Option endO = SJ.j().attrsFlattenToMap().get("end"); + + // Option.getOrElse did not compile, so this dirty workaround + String start = ""; + String end = ""; + + if (startO.isDefined()) { start = startO.get(); } + if (endO.isDefined()) { end = endO.get(); } + + codeListing = formatCodeListing(code, start, end ); + +// System.out.println("CODE: "+codeListing); + + Elem el = elem("div", attr("style", "text-align: center"), + elem("tt", + text("Listing:"), + elem("a", attr("href", "https://github.com/lift/seventhings/tree/liftj/src/main/" + gitDir(fileName) + fileName), + text(fileName))), + elem("pre", attr("class", "listing brush: "+calcBrush(fileName)), text(codeListing))); + + return toNodeSeq(el); + } + } + return scala.xml.NodeSeq.seqToNodeSeq(new Text("Failure").theSeq()); + + } + + + private String formatCodeListing(byte[] code, String start, String end) { + + boolean startDefined = (start == null || start.isEmpty()) ? false : true; + boolean startFound = false; + boolean endDefined = (end == null || end.isEmpty()) ? false : true; + boolean endFound = false; + boolean firstLineAfterStartRead = startDefined ? false : true; + + try { + String[] rawCodeArr = new String(code, "UTF-8").split("\\n"); + List rawCode = new ArrayList(); + for (String s : rawCodeArr) { + String s2 = s.replace("\t", " "); + if (startDefined && !startFound) { + if (s2.indexOf(start) > -1) { + startFound = true; + } else { + continue; + } + } + if (endDefined && firstLineAfterStartRead) { + if (!endFound) { + if (s2.indexOf(end) > -1) { + endFound = true; + continue; + } + } else { + continue; + } + } + rawCode.add(s2); + + if (startFound) { + firstLineAfterStartRead = true; + } + } + + StringBuilder sb = new StringBuilder(); + for (String s : rawCode) { + sb.append(s).append("\n"); + } + + return sb.toString(); + + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e); + } + + } + +} diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/comet/.keep b/src/main/resources/src/scala/net/liftweb/seventhings/comet/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/lib/BoxJBridge.scala b/src/main/resources/src/scala/net/liftweb/seventhings/lib/BoxJBridge.scala new file mode 100644 index 0000000..d96a1ea --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/lib/BoxJBridge.scala @@ -0,0 +1,10 @@ +package net.liftweb.seventhings.lib + +import net.liftweb.common.{EmptyBox, Box, Empty} + +class BoxJBridge { + + def empty: EmptyBox = Empty + + +} \ No newline at end of file diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/lib/HelpersJBridge.scala b/src/main/resources/src/scala/net/liftweb/seventhings/lib/HelpersJBridge.scala new file mode 100644 index 0000000..1de6518 --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/lib/HelpersJBridge.scala @@ -0,0 +1,14 @@ +package net.liftweb.seventhings.lib + +import net.liftweb.util._ + +/** + * I was not able to just return the Helpers object. the compiler complained it found Helpers$ instead of Helpers. + */ +class HelpersJBridge extends TimeHelpers with StringHelpers with ListHelpers +with SecurityHelpers with BindHelpers with HttpHelpers +with IoHelpers with BasicTypesHelpers +with ClassHelpers with ControlHelpers +{ + +} \ No newline at end of file diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/lib/JqJsCmdsJBridge.scala b/src/main/resources/src/scala/net/liftweb/seventhings/lib/JqJsCmdsJBridge.scala new file mode 100644 index 0000000..c856926 --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/lib/JqJsCmdsJBridge.scala @@ -0,0 +1,7 @@ +package net.liftweb.seventhings.lib + +class JqJsCmdsJBridge { + + def unblock = net.liftweb.http.js.jquery.JqJsCmds.Unblock + +} \ No newline at end of file diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/lib/TopScopeJBridge.scala b/src/main/resources/src/scala/net/liftweb/seventhings/lib/TopScopeJBridge.scala new file mode 100644 index 0000000..7dd2a92 --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/lib/TopScopeJBridge.scala @@ -0,0 +1,10 @@ + +package net.liftweb.seventhings.lib + +import xml.TopScope + +class TopScopeJBridge { + + def topScope = TopScope + +} \ No newline at end of file diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/lib/WiringUIBridge.scala b/src/main/resources/src/scala/net/liftweb/seventhings/lib/WiringUIBridge.scala new file mode 100644 index 0000000..fb4f6df --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/lib/WiringUIBridge.scala @@ -0,0 +1,10 @@ +package net.liftweb.seventhings.lib + +import net.liftweb.http.WiringUI + +class WiringUIBridge { + + def wiringUI = WiringUI + + +} \ No newline at end of file diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/lib/WizardJ.scala b/src/main/resources/src/scala/net/liftweb/seventhings/lib/WizardJ.scala new file mode 100644 index 0000000..c15b15a --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/lib/WizardJ.scala @@ -0,0 +1,21 @@ +package net.liftweb.seventhings.lib + +import net.liftweb.wizard.Wizard + + +abstract class WizardJ extends Wizard { + + abstract class ScreenJ extends Screen { + + /* + protected def field[T](underlying: => BaseField{type ValueType=T}, + stuff: FilterOrValidate[T]*)(implicit man: Manifest[T]): Field{type ValueType=T} = { + + */ + // field(java.lang.String,java.lang.String,scala.Function1>,scala.Function1>) + + def fieldj(s1: String, arg2: scala.Function1[java.lang.String, scala.collection.immutable.List[net.liftweb.util.FieldError]]*) = field(s1, arg2) + + } + +} \ No newline at end of file diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/lib/XmlJBridge.scala b/src/main/resources/src/scala/net/liftweb/seventhings/lib/XmlJBridge.scala new file mode 100644 index 0000000..f63cf3d --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/lib/XmlJBridge.scala @@ -0,0 +1,22 @@ + +package net.liftweb.seventhings.lib + +import xml.{Elem, Null, TopScope} +import net.liftweb.http.SHtml +import net.liftweb.http.SHtml.BasicElemAttr + +class XmlJBridge { + + def topScope = TopScope + + def getNull = Null + + def noopElemAttr = BasicElemAttr("dummy", "dummy") + +} + +//class NoopElemAttr extends BasicElemAttr { +// override def apply(e: Elem): Elem = e +//} + + diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/lib/XmlNullJBridge.scala b/src/main/resources/src/scala/net/liftweb/seventhings/lib/XmlNullJBridge.scala new file mode 100644 index 0000000..c22533b --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/lib/XmlNullJBridge.scala @@ -0,0 +1,15 @@ +/* + * Created by IntelliJ IDEA. + * User: tuhlmann + * Date: 11.02.11 + * Time: 10:39 + */ +package net.liftweb.seventhings.lib + +import xml.Null + +class XmlNullJBridge { + + def getNull = Null + +} \ No newline at end of file diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/model/.keep b/src/main/resources/src/scala/net/liftweb/seventhings/model/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/snippet/InvoiceWiring.scala b/src/main/resources/src/scala/net/liftweb/seventhings/snippet/InvoiceWiring.scala new file mode 100644 index 0000000..77664e5 --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/snippet/InvoiceWiring.scala @@ -0,0 +1,113 @@ +package net.liftweb.seventhings +package snippet + +import net.liftweb._ +import http._ +import SHtml._ +import util._ +import Helpers._ +import js._ +import js.JsCmds._ +import js.jquery._ + +import scala.xml.{NodeSeq, Text} + +case class Line(guid: String, name: String, price: Double, taxable: Boolean) + +/** + * An invoice system with subtotals, tax, etc. + */ +class InvoiceWiring { + /** + * Define the relationships among the items + */ + private object Info { + val invoices = ValueCell(List(newLine)) + val taxRate = ValueCell(0.05d) + val subtotal = invoices.lift(_.foldLeft(0d)(_ + _.price)) + val taxable = invoices.lift(_.filter(_.taxable). + foldLeft(0D)(_ + _.price)) + + val tax = taxRate.lift(taxable) {_ * _} + + val total = subtotal.lift(tax) {_ + _} + } + + /** + * wire an element to subtotal + */ + def subtotal = WiringUI.toNode(Info.subtotal)(doubleDraw) + + /** + * Wire an element to taxable + */ + def taxable = WiringUI.toNode(Info.taxable)(doubleDraw) + + def tax = WiringUI.toNode(Info.tax, JqWiringSupport.fade)(doubleDraw) + + def total = WiringUI.toNode(Info.total, JqWiringSupport.fade)(doubleDraw) + + + /** * + * The tax rate input + */ + def taxRate = ajaxText(Info.taxRate.get.toString, + doubleToJsCmd(Info.taxRate.set)) + + /** + * Draw all the input lines + */ + def showLines = "* *" #> (Info.invoices.get.flatMap(renderLine): NodeSeq) + + /** + * Add a line to the input + */ + def addLine = + "* [onclick]" #> ajaxInvoke(() => + JqJsCmds.AppendHtml("invoice_lines", renderLine(appendLine))) + + /** + * render a line of input fields + */ + private def renderLine(theLine: Line): NodeSeq = { + import theLine._ + +
+ {ajaxText(name, s => mutateLine(guid)(_.copy(name = s)))} + + {ajaxText(price.toString, + (d: Double) => mutateLine(guid) {_.copy(price = d)})} + + {ajaxCheckbox(theLine.taxable, + b => mutateLine(guid) {_.copy(taxable = b)})} +
+ } + + private def newLine = Line(nextFuncName, "", 0, false) + + private def appendLine: Line = { + val ret = newLine + Info.invoices.set(ret :: Info.invoices.get) + ret + } + + /** + * Mutate a line and update the Info field + */ + private def mutateLine(guid: String)(f: Line => Line) { + val all = Info.invoices.get + val head = all.filter(_.guid == guid).map(f) + val rest = all.filter(_.guid != guid) + Info.invoices.set(head ::: rest) + } + + // convert a Double to a NodeSeq + private def doubleDraw: (Double, NodeSeq) => NodeSeq = + (d, ns) => Text(java.text.NumberFormat.getCurrencyInstance.format(d)) + + + // Some helpful implicit conversions + private implicit def unitToJsCmd(in: Unit): JsCmd = Noop + private implicit def doubleToJsCmd(in: Double => Any): String => JsCmd = + str => {asDouble(str).foreach(in)} +} diff --git a/src/main/scala/net/liftweb/seventhings/snippet/MyWizard.scala b/src/main/resources/src/scala/net/liftweb/seventhings/snippet/MyWizard.scala similarity index 93% rename from src/main/scala/net/liftweb/seventhings/snippet/MyWizard.scala rename to src/main/resources/src/scala/net/liftweb/seventhings/snippet/MyWizard.scala index 7eac2d4..dddf7e8 100644 --- a/src/main/scala/net/liftweb/seventhings/snippet/MyWizard.scala +++ b/src/main/resources/src/scala/net/liftweb/seventhings/snippet/MyWizard.scala @@ -4,7 +4,6 @@ package snippet import net.liftweb._ import http._ import js.jquery.JqJsCmds._ -import util.Func0 import wizard._ import util.Helpers._ @@ -33,7 +32,7 @@ object MyWizard extends Wizard { val parentName = new Screen { val parentName = field(S ? "Mom or Dad's name", "", valMinLen(2, S ? "Name Too Short"), - valMaxLen(40, S ? "Name Too Long")) + valMaxLen(40, S ? "Name Too Long")) } // we ask for the favorite pet @@ -51,6 +50,6 @@ object MyWizard extends Wizard { } } -object AjaxRunnerScala { +object AjaxRunner { def render = "* [onclick]" #> SHtml.ajaxInvoke(() => ModalDialog(
)) } diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/snippet/MyWizardScala.scala b/src/main/resources/src/scala/net/liftweb/seventhings/snippet/MyWizardScala.scala new file mode 100644 index 0000000..3d2db25 --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/snippet/MyWizardScala.scala @@ -0,0 +1,64 @@ +package net.liftweb.seventhings +package snippet + +import net.liftweb._ +import http._ +import js.jquery.JqJsCmds._ +import util.Func0 +import wizard._ +import util.Helpers._ +import lib.WizardJ + +/** + * An example of a wizard in Lift + */ +class MyWizardScala extends Wizard { + + // define the first screen + class NameAndAgeScreen extends Screen { + // it has a name field + val name = field(S ? "First Name", "", + valMinLen(2, S ? "Name Too Short"), + valMaxLen(40, S ? "Name Too Long")) + + // and an age field + val age = field(S ? "Age", 0, minVal(5, S ?? "Too young"), + maxVal(120, S ? "You should be dead")) + + // choose the next screen based on the age + override def nextScreen = if (age.is < 18) parentName else favoritePet + } + + // We ask the parent's name if the person is under 18 + class ParentNameScreen extends Screen { + val parentName = field(S ? "Mom or Dad's name", "", + valMinLen(2, S ? "Name Too Short"), + valMaxLen(40, S ? "Name Too Long")) + } + + // we ask for the favorite pet + class FavoritePetScreen extends Screen { + val petName = field(S ? "Pet's name", "", + valMinLen(2, S ? "Name Too Short"), + valMaxLen(40, S ? "Name Too Long")) + } + + // what to do on completion of the wizard + def finish() { + S.notice("Thank you for registering your pet: "+ + favoritePet.petName+ + " your age * 3: "+nameAndAge.age * 3) + } + + val nameAndAge = new NameAndAgeScreen + val parentName = new ParentNameScreen + val favoritePet = new FavoritePetScreen + + def getNameAndAge = nameAndAge + + def getParentName = parentName + + def getFavoritePet = favoritePet + +} + diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/snippet/ShowCodeScala.scala b/src/main/resources/src/scala/net/liftweb/seventhings/snippet/ShowCodeScala.scala new file mode 100644 index 0000000..737b300 --- /dev/null +++ b/src/main/resources/src/scala/net/liftweb/seventhings/snippet/ShowCodeScala.scala @@ -0,0 +1,67 @@ +package net.liftweb.seventhings +package snippet + +import net.liftweb._ +import http._ +import util._ +import Helpers._ +import common._ + +import scala.xml.NodeSeq + +/** + * A snippet that will show part or all of a source file + * that's part of this project + */ +object ShowCodeScala { + def render: NodeSeq = + for { + fileName <- S.attr("name") ?~ "Name missing" + + code <- (LiftRules.loadResource("/src/scala"+fileName) or + LiftRules.loadResource("/src/webapp"+fileName)) ?~ + ("Cannot find "+fileName) + + } yield { + def calcBrush = if (fileName.endsWith(".html") || + fileName.endsWith(".xml")) "html" else "scala" + + def gitDir = if (fileName.endsWith(".html") || + fileName.endsWith(".xml")) "webapp" else "scala" + + val start = S.attr("start") + val end = S.attr("end") + + val rawCode = (new String(code, "UTF-8"). + split("""\n"""). + toList.map(_.replace("\t", " "))). + dropWhile(s => start.map(st => s.indexOf(st) < 0) openOr false) match { + case Nil => Nil + case x :: xs => x :: xs. + takeWhile(s => end.map(en => s.indexOf(en) < 0) openOr true) + } + + + + +
Listing: + {fileName} +
{rawCode.mkString("\n")}
+
+ } + + private implicit def boxNStoNS(in: Box[NodeSeq]): NodeSeq = + in match { + case Full(ns) => ns + case Failure(msg, _, _) => +
+ Failed to look up source: {msg} +
+ case _ =>
+ Failed to look up source +
+ + + } +} diff --git a/src/main/resources/src/scala/net/liftweb/seventhings/view/.keep b/src/main/resources/src/scala/net/liftweb/seventhings/view/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/src/webapp/WEB-INF/web.xml b/src/main/resources/src/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..6774710 --- /dev/null +++ b/src/main/resources/src/webapp/WEB-INF/web.xml @@ -0,0 +1,21 @@ + + + + + + + LiftFilter + Lift Filter + The Filter that intercepts lift calls + net.liftweb.http.LiftFilter + + + + + LiftFilter + /* + + + diff --git a/src/main/resources/src/webapp/comet.html b/src/main/resources/src/webapp/comet.html new file mode 100644 index 0000000..c3a1a0f --- /dev/null +++ b/src/main/resources/src/webapp/comet.html @@ -0,0 +1,137 @@ + + + + + Comet + + +
+

+ + + One of Lift's key features in Comet (or server push) + support and associated Ajax support. + This page contains a multi-user chat application + with Comet (server-push) that updates the browser + when anyone sends a chat message. There's an + input box that allows the user to send a line into + the chat and that's done via an asynchronous call to + the server (the page is not reloaded as part of the call). + + +

+ +
+
    +
  • Line 1
  • +
  • Line 2
  • +
  • Line 3
  • +
+ +
+ + +
+
+ + + + Let's take a look at the markup for the + Comet (server pushed list of chat items) + part of the application: + + +
view code
+ +
+ + + We simply define the markup and mark the <ul> tag + with a snippet invocation that loads the Chat + Comet component. Let's look at the Chat + component. + + +
+ +
view code
+ + +
+ + + Once again, something that's hard or impossible + in other web frameworks is is trivial in Lift. + The developer doesn't worry about the plumbing of how + the browser polls for changes. By default Lift uses + long polling and multiplexes multiple comet components + into a single long poll, but when web sockets are + standardized, Lift will automatically support them + without requiring any code changes. The developer + focuses on the semantics of "when this changes on the + server, update the component" and Lift takes care of the + rest. + + +
+ +
+ +
+ + + Note that you can attempt to attack the site with + a cross site scripting attack (e.g., type <script>alert('I ownz your machine')</script> into the chat box). You'll see that Lift + properly escapes the input without any developer intervention. + + +
+ +
+ +
+ + + Let's take a look at the markup for the Ajax input form: + + +
+ +
view code
+ +
+ + + We designate the form as Ajax with the Form.ajax + snippet. The text input invokes the ChatIn + snippet. Let's look at that snippet: + + +
+ +
view code
+ +
+ + + Once again, we didn't need to do any plumbing. Lift + takes care of associating the behavior (sending the input + String to the ChatServer.) We didn't + set up routes or anything else. Further, this code is + resistant to replay attacks because the automatically + generated routes are dynamic and random and cannot + be predicted. And in case you're worried about doing + things via standard REST calls, Lift has + excellent REST support. + And Lift supports Comet for data as well as + HTML, so you can use Lift to serve your + Cappuccino, + SproutCore, ExtJS, etc. apps and get full Comet support. + + +
+ + +
+ + diff --git a/src/main/resources/src/webapp/css/shCore.css b/src/main/resources/src/webapp/css/shCore.css new file mode 100644 index 0000000..34f6864 --- /dev/null +++ b/src/main/resources/src/webapp/css/shCore.css @@ -0,0 +1,226 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + -moz-border-radius: 0 0 0 0 !important; + -webkit-border-radius: 0 0 0 0 !important; + background: none !important; + border: 0 !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} + +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .bold { + font-weight: bold !important; +} +.syntaxhighlighter .italic { + font-style: italic !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 0 0.5em 0 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 0 1em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { + padding-left: 0em !important; +} +.syntaxhighlighter.show { + display: block !important; +} +.syntaxhighlighter.collapsed table { + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar { + padding: 0.1em 0.8em 0em 0.8em !important; + font-size: 1em !important; + position: static !important; + width: auto !important; + height: auto !important; +} +.syntaxhighlighter.collapsed .toolbar span { + display: inline !important; + margin-right: 1em !important; +} +.syntaxhighlighter.collapsed .toolbar span a { + padding: 0 !important; + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar span a.expandSource { + display: inline !important; +} +.syntaxhighlighter .toolbar { + position: absolute !important; + right: 1px !important; + top: 1px !important; + width: 11px !important; + height: 11px !important; + font-size: 10px !important; + z-index: 10 !important; +} +.syntaxhighlighter .toolbar span.title { + display: inline !important; +} +.syntaxhighlighter .toolbar a { + display: block !important; + text-align: center !important; + text-decoration: none !important; + padding-top: 1px !important; +} +.syntaxhighlighter .toolbar a.expandSource { + display: none !important; +} +.syntaxhighlighter.ie { + font-size: .9em !important; + padding: 1px 0 1px 0 !important; +} +.syntaxhighlighter.ie .toolbar { + line-height: 8px !important; +} +.syntaxhighlighter.ie .toolbar a { + padding-top: 0px !important; +} +.syntaxhighlighter.printing .line.alt1 .content, +.syntaxhighlighter.printing .line.alt2 .content, +.syntaxhighlighter.printing .line.highlighted .number, +.syntaxhighlighter.printing .line.highlighted.alt1 .content, +.syntaxhighlighter.printing .line.highlighted.alt2 .content { + background: none !important; +} +.syntaxhighlighter.printing .line .number { + color: #bbbbbb !important; +} +.syntaxhighlighter.printing .line .content { + color: black !important; +} +.syntaxhighlighter.printing .toolbar { + display: none !important; +} +.syntaxhighlighter.printing a { + text-decoration: none !important; +} +.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { + color: black !important; +} +.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { + color: #008200 !important; +} +.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { + color: blue !important; +} +.syntaxhighlighter.printing .keyword { + color: #006699 !important; + font-weight: bold !important; +} +.syntaxhighlighter.printing .preprocessor { + color: gray !important; +} +.syntaxhighlighter.printing .variable { + color: #aa7700 !important; +} +.syntaxhighlighter.printing .value { + color: #009900 !important; +} +.syntaxhighlighter.printing .functions { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .constants { + color: #0066cc !important; +} +.syntaxhighlighter.printing .script { + font-weight: bold !important; +} +.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { + color: gray !important; +} +.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { + color: red !important; +} +.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { + color: black !important; +} diff --git a/src/main/resources/src/webapp/css/shThemeDefault.css b/src/main/resources/src/webapp/css/shThemeDefault.css new file mode 100644 index 0000000..b6c6bbd --- /dev/null +++ b/src/main/resources/src/webapp/css/shThemeDefault.css @@ -0,0 +1,117 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter { + background-color: white !important; +} +.syntaxhighlighter .line.alt1 { + background-color: #eee !important; +} +.syntaxhighlighter .line.alt2 { + background-color: white !important; +} +.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { + background-color: #e0e0e0 !important; +} +.syntaxhighlighter .line.highlighted.number { + color: black !important; +} +.syntaxhighlighter table caption { + color: black !important; +} +.syntaxhighlighter .gutter { + color: #afafaf !important; +} +.syntaxhighlighter .gutter .line { + border-right: 3px solid #6ce26c !important; +} +.syntaxhighlighter .gutter .line.highlighted { + background-color: #6ce26c !important; + color: white !important; +} +.syntaxhighlighter.printing .line .content { + border: none !important; +} +.syntaxhighlighter.collapsed { + overflow: visible !important; +} +.syntaxhighlighter.collapsed .toolbar { + color: blue !important; + background: white !important; + border: 1px solid #6ce26c !important; +} +.syntaxhighlighter.collapsed .toolbar a { + color: blue !important; +} +.syntaxhighlighter.collapsed .toolbar a:hover { + color: red !important; +} +.syntaxhighlighter .toolbar { + color: white !important; + background: #6ce26c !important; + border: none !important; +} +.syntaxhighlighter .toolbar a { + color: white !important; +} +.syntaxhighlighter .toolbar a:hover { + color: black !important; +} +.syntaxhighlighter .plain, .syntaxhighlighter .plain a { + color: black !important; +} +.syntaxhighlighter .comments, .syntaxhighlighter .comments a { + color: #008200 !important; +} +.syntaxhighlighter .string, .syntaxhighlighter .string a { + color: blue !important; +} +.syntaxhighlighter .keyword { + color: #006699 !important; +} +.syntaxhighlighter .preprocessor { + color: gray !important; +} +.syntaxhighlighter .variable { + color: #aa7700 !important; +} +.syntaxhighlighter .value { + color: #009900 !important; +} +.syntaxhighlighter .functions { + color: #ff1493 !important; +} +.syntaxhighlighter .constants { + color: #0066cc !important; +} +.syntaxhighlighter .script { + font-weight: bold !important; + color: #006699 !important; + background-color: none !important; +} +.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { + color: gray !important; +} +.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { + color: red !important; +} + +.syntaxhighlighter .keyword { + font-weight: bold !important; +} diff --git a/src/main/resources/src/webapp/images/ajax-loader.gif b/src/main/resources/src/webapp/images/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..7c12c21fcb05ccbc90eb90202c96fb4578f8066d GIT binary patch literal 2608 zcmdVcdr(tX9tZGCZgP`cV{Tp-NWvpvKt|wv@-B&^pMYg=krz)&_+_N{pyjc|;8*19IJuz|8@Xac3z#I4;0G5`P005Yqn;RP&>+S9B=;&x_YO>jE27{r#zTR%P zTdh{TUf`T5Ma4#l}?>0I+(4~ic~qOyf^o%GJ~@BX!Zg=&&UAm z+}USoRYG)1G8QS14h;$cU7SlBmJhUy06}sZEy`A?|oBLVej0 z{z`KDk;1@TJv%DaZru@bU9(YON(Ti`4DSo!U;&V?$SOb&u1bRU(u)*K1ZDvwH@-l7 zk^x6$7Sq`rl@RhQQIk{hfrbOS@~M(kHJf_?`)brZ5q+td(cY#P4vfnwNl>m$%KJ){OneHJ4@0=g9!DrUy~?1lPl zRal?ki+4uXzL6}p=jbT6S+UU~ z7G>+Qo12-ER3)3M!@N8{Mm+$M=FF!U)Po`*{-*&9(M|^9|hccTp|4A zL~jpoW@1WtZ-RwyyX%1Q_*)JHPq^x+QYL;r!O_SwRHtj-l(YrX5?b}O<_b5T`YGKa z4`#XemQ1B5nTFWnw*~xk?ih8%y}DX3d^&^5lx--mbnc_aFb7MkZH;BA4*MxakR#7C zuDj(L_vJ|EeR_VcNdFt4{clD6yN{ZYjs2)|TtQALs?EvPybk;z!#$&|W^2rD-HY;kGHTWf>dB6Btm4D(K*=2tW zO-GMV81(Y?pWYeyS8r70)$t+jG^%NpP(k76x<#FzrBXs!A8VZXGVT9qWrRr zcUDZb#GhC$`Efo%VP!A%;sLa^{& z5xwRf3cQfX$s_swIkA2BZmBBGGM6Mi>>C)J*7=Yb9lDwp*9AUw)cz*NYB{>*YN|W; zrQp%nbG~h7qjyUy1623LwmQ*@6ZL0KzZZwN!Yj>|vapX>r`RAeI((Vq?bPbPy_a_$ z@!gtP=xqP`u5?iH#LzoQ3tr4m%POD)tM^C2j2(blz;}}`x0^PLu?r*Dp`MUX#bF=Q zk}+xl;B^4lRgezQa@pLECEOORGrzOO~DVbTvNx%H!PE(OYE zjY?R#(DbNHJ2gF{-FC-5p^eWSnI6wJYlo(9>`d$*9n5VUmL#uN1a0mGTB;uCZ?E6n z1%%@@B2q|F3*;BRDT;k1i0KvZB&>bRFX(jB-$sWjS + + + + Home + + + +
+

Lift is the most powerful, most secure web framework +available today.  Yeah, it's a bold claim, but this site is going +to show you 7 things that are hard or impossible in other web +frameworks.  These seven things are crucial to building and +maintaining interactive, secure web sites.  Each of the seven +things has the source code right on the page.  This will let you +see why Lift is different and better.

+
    +
  1. Lazy Loading
  2. +
  3. Parallel page rendering
  4. +
  5. Comet and Ajax
  6. +
  7. Wiring -- declare interdepencies between page elements
  8. +
  9. Designer friendly templates
  10. +
  11. Wizard -- multipage input screens with full back-button +support
  12. +
  13. Security
    +
  14. +
+Lift gives you the above Seven Things, plus your code is +concise and maintainable, Lift's performance and +scalability, and all the benefits of deploying your application on +battle-tested J/EE infrastructure. +
+ + diff --git a/src/main/resources/src/webapp/lazy.html b/src/main/resources/src/webapp/lazy.html new file mode 100644 index 0000000..6efb4f6 --- /dev/null +++ b/src/main/resources/src/webapp/lazy.html @@ -0,0 +1,63 @@ + + + + + Lazy + + +
+

Lift has built-in Lazy Loading.

+

+

+
+ I started this computation at + start and it + completed at end. + +
+ Notice the spinning icon above this paragraph?  That + icon indicates that a computation is going on.  The page was + rendered back to the browser and when the computation for that part of + screen real-estate is complete, the HTML will be delivered to the + browser.  And, you can have more than one lazy loaded components + on the same page:
+
+
I started this computation at start and it + completed at end.
+
+
+ How hard is the code? Here's the display part of the code:
+
+
view code
+ +
+ + + That's not a lot of markup code. Just mark the + block of markup that's going to take a long time to + calculate. Lift takes care of the rest. + Let's look at the snippet code: + + +
+ +
view code
+ + +
+ + + Most other frameworks don't have lazy loading as part of + the core framework. It's generally very hard to do, but + because Lift has excellent + comet + support, it's easy to "push" content from the + server to the browser. + + +
+ + +
+ + diff --git a/src/main/resources/src/webapp/parallel.html b/src/main/resources/src/webapp/parallel.html new file mode 100644 index 0000000..84cd0fa --- /dev/null +++ b/src/main/resources/src/webapp/parallel.html @@ -0,0 +1,103 @@ + + + + + Parallel + + +
+

+ + + Lift can parallelize page rendering. + This is a huge win if you need to consult external + servers while rendering a page. If you need to + go out to 10 different ad servers and each one takes + half a second to respond, you want to run those in parallel: + + +

+ +
+ Ad server #1: The Ad +
+ +
+ Ad server #2: The Ad +
+ +
+ Ad server #3: The Ad +
+ +
+ Ad server #4: The Ad +
+ +
+ Ad server #5: The Ad +
+ +
+ Ad server #6: The Ad +
+ +
+ Ad server #7: The Ad +
+ +
+ Ad server #8: The Ad +
+ +
+ Ad server #9: The Ad +
+ +
+ Ad server #10: The Ad +
+ + + + + The markup is very simple: + + +
view code
+ +
+ + + That's not a lot of markup code. When you mark the + snippet as parallel, Lift forwards the + snippet calculation to another thread in a pool + of threads. Lift continues to evaluate the markup + on the page in parallel and recombines the results + before the page is sent to the browser. + Let's look at the snippet code: + + +
+ +
view code
+ + +
+ + + Once again, something that's hard or impossible + in other web frameworks is is trivial in Lift. + How much does this matter? Is your page load time + slow because you're going out to lots and lots of + different back end servers while composing a page? + Lift makes that kind of work parallelizable. + + +
+ + +
+ + diff --git a/src/main/resources/src/webapp/scripts/jquery.blockUI.js b/src/main/resources/src/webapp/scripts/jquery.blockUI.js new file mode 100644 index 0000000..fe1144a --- /dev/null +++ b/src/main/resources/src/webapp/scripts/jquery.blockUI.js @@ -0,0 +1,490 @@ +/*! + * jQuery blockUI plugin + * Version 2.36 (16-NOV-2010) + * @requires jQuery v1.2.3 or later + * + * Examples at: http://malsup.com/jquery/block/ + * Copyright (c) 2007-2008 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 + * + * 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; + +var noOp = function() {}; + +// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle +// retarded userAgent strings on Vista) +var mode = document.documentMode || 0; +var setExpr = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8); +var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent) && !mode; + +// 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; + $.blockUI({ + message: $m, fadeIn: 700, fadeOut: 1000, centerY: false, + timeout: timeout, showOverlay: false, + onUnblock: onClose, + 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.35; // 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' + }, + + // 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) + 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, + + // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity) + 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, + + // 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' +}; + +// private data and functions follow... + +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 || {}); + var 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 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 (by default) + // layer3 is the message content that is displayed while blocking + + var lyr1 = ($.browser.msie || opts.forceIframe) + ? $('') + : $(''); + var lyr2 = $(''); + + var lyr3, s; + if (opts.theme && full) { + 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.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 || 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 && (!$.boxModel || $('object,embed', full ? null : el).length > 0); + if (ie6 || expr) { + // 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); + } + }); + } + + // 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 (($.browser.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 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'); + } + opts = $.extend({}, $.blockUI.defaults, opts || {}); + bind(0, el, opts); // unbind events + + var els; + if (full) // crazy selector to handle odd field errors in ie6/7 + els = $('body').children().filter('.blockUI').add('body > .blockUI'); + else + els = $('.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); + $(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); + + // don't bind events when overlay is not in use or if bindEvents is false + if (!opts.bindEvents || (b && !opts.showOverlay)) + 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; + } + } + } + var opts = e.data; + // allow events within the message content + if ($(e.target).parents('div.' + opts.blockMsgClass).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); diff --git a/src/main/resources/src/webapp/scripts/shBrushBash.js b/src/main/resources/src/webapp/scripts/shBrushBash.js new file mode 100644 index 0000000..ca43c35 --- /dev/null +++ b/src/main/resources/src/webapp/scripts/shBrushBash.js @@ -0,0 +1,30 @@ +SyntaxHighlighter.brushes.Bash = function() +{ + var keywords = 'if fi then elif else for do done until while break continue case function return in eq ne gt lt ge le'; + var commands = 'alias apropos awk bash bc bg builtin bzip2 cal cat cd cfdisk chgrp chmod chown chroot' + + 'cksum clear cmp comm command cp cron crontab csplit cut date dc dd ddrescue declare df ' + + 'diff diff3 dig dir dircolors dirname dirs du echo egrep eject enable env ethtool eval ' + + 'exec exit expand export expr false fdformat fdisk fg fgrep file find fmt fold format ' + + 'free fsck ftp gawk getopts grep groups gzip hash head history hostname id ifconfig ' + + 'import install join kill less let ln local locate logname logout look lpc lpr lprint ' + + 'lprintd lprintq lprm ls lsof make man mkdir mkfifo mkisofs mknod more mount mtools ' + + 'mv netstat nice nl nohup nslookup open op passwd paste pathchk ping popd pr printcap ' + + 'printenv printf ps pushd pwd quota quotacheck quotactl ram rcp read readonly renice ' + + 'remsync rm rmdir rsync screen scp sdiff sed select seq set sftp shift shopt shutdown ' + + 'sleep sort source split ssh strace su sudo sum symlink sync tail tar tee test time ' + + 'times touch top traceroute trap tr true tsort tty type ulimit umask umount unalias ' + + 'uname unexpand uniq units unset unshar useradd usermod users uuencode uudecode v vdir ' + + 'vi watch wc whereis which who whoami Wget xargs yes' + ; + + this.regexList = [ + { regex: SyntaxHighlighter.regexLib.singleLinePerlComments, css: 'comments' }, // one line comments + { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings + { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // keywords + { regex: new RegExp(this.getKeywords(commands), 'gm'), css: 'functions' } // commands + ]; +} + +SyntaxHighlighter.brushes.Bash.prototype = new SyntaxHighlighter.Highlighter(); +SyntaxHighlighter.brushes.Bash.aliases = ['bash', 'shell']; + diff --git a/src/main/resources/src/webapp/scripts/shBrushJava.js b/src/main/resources/src/webapp/scripts/shBrushJava.js new file mode 100644 index 0000000..d692fd6 --- /dev/null +++ b/src/main/resources/src/webapp/scripts/shBrushJava.js @@ -0,0 +1,57 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +;(function() +{ + // CommonJS + typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; + + function Brush() + { + var keywords = 'abstract assert boolean break byte case catch char class const ' + + 'continue default do double else enum extends ' + + 'false final finally float for goto if implements import ' + + 'instanceof int interface long native new null ' + + 'package private protected public return ' + + 'short static strictfp super switch synchronized this throw throws true ' + + 'transient try void volatile while'; + + this.regexList = [ + { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments + { regex: /\/\*([^\*][\s\S]*)?\*\//gm, css: 'comments' }, // multiline comments + { regex: /\/\*(?!\*\/)\*[\s\S]*?\*\//gm, css: 'preprocessor' }, // documentation comments + { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // strings + { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings + { regex: /\b([\d]+(\.[\d]+)?|0x[a-f0-9]+)\b/gi, css: 'value' }, // numbers + { regex: /(?!\@interface\b)\@[\$\w]+\b/g, css: 'color1' }, // annotation @anno + { regex: /\@interface\b/g, css: 'color2' }, // @interface keyword + { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // java keyword + ]; + + this.forHtmlScript({ + left : /(<|<)%[@!=]?/g, + right : /%(>|>)/g + }); + }; + + Brush.prototype = new SyntaxHighlighter.Highlighter(); + Brush.aliases = ['java']; + + SyntaxHighlighter.brushes.Java = Brush; + + // CommonJS + typeof(exports) != 'undefined' ? exports.Brush = Brush : null; +})(); diff --git a/src/main/resources/src/webapp/scripts/shBrushScala.js b/src/main/resources/src/webapp/scripts/shBrushScala.js new file mode 100644 index 0000000..4b0b6f0 --- /dev/null +++ b/src/main/resources/src/webapp/scripts/shBrushScala.js @@ -0,0 +1,51 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +;(function() +{ + // CommonJS + typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; + + function Brush() + { + // Contributed by Yegor Jbanov and David Bernard. + + var keywords = 'val sealed case def true trait implicit forSome import match object null finally super ' + + 'override try lazy for var catch throw type extends class while with new final yield abstract ' + + 'else do if return protected private this package false'; + + var keyops = '[_:=><%#@]+'; + + this.regexList = [ + { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments + { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments + { regex: SyntaxHighlighter.regexLib.multiLineSingleQuotedString, css: 'string' }, // multi-line strings + { regex: SyntaxHighlighter.regexLib.multiLineDoubleQuotedString, css: 'string' }, // double-quoted string + { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings + { regex: /0x[a-f0-9]+|\d+(\.\d+)?/gi, css: 'value' }, // numbers + { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // keywords + { regex: new RegExp(keyops, 'gm'), css: 'keyword' } // scala keyword + ]; + } + + Brush.prototype = new SyntaxHighlighter.Highlighter(); + Brush.aliases = ['scala']; + + SyntaxHighlighter.brushes.Scala = Brush; + + // CommonJS + typeof(exports) != 'undefined' ? exports.Brush = Brush : null; +})(); diff --git a/src/main/resources/src/webapp/scripts/shBrushXml.js b/src/main/resources/src/webapp/scripts/shBrushXml.js new file mode 100644 index 0000000..69d9fd0 --- /dev/null +++ b/src/main/resources/src/webapp/scripts/shBrushXml.js @@ -0,0 +1,69 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +;(function() +{ + // CommonJS + typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; + + function Brush() + { + function process(match, regexInfo) + { + var constructor = SyntaxHighlighter.Match, + code = match[0], + tag = new XRegExp('(<|<)[\\s\\/\\?]*(?[:\\w-\\.]+)', 'xg').exec(code), + result = [] + ; + + if (match.attributes != null) + { + var attributes, + regex = new XRegExp('(? [\\w:\\-\\.]+)' + + '\\s*=\\s*' + + '(? ".*?"|\'.*?\'|\\w+)', + 'xg'); + + while ((attributes = regex.exec(code)) != null) + { + result.push(new constructor(attributes.name, match.index + attributes.index, 'color1')); + result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string')); + } + } + + if (tag != null) + result.push( + new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword') + ); + + return result; + } + + this.regexList = [ + { regex: new XRegExp('(\\<|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\>|>)', 'gm'), css: 'color2' }, // + { regex: SyntaxHighlighter.regexLib.xmlComments, css: 'comments' }, // + { regex: new XRegExp('(<|<)[\\s\\/\\?]*(\\w+)(?.*?)[\\s\\/\\?]*(>|>)', 'sg'), func: process } + ]; + }; + + Brush.prototype = new SyntaxHighlighter.Highlighter(); + Brush.aliases = ['xml', 'xhtml', 'xslt', 'html']; + + SyntaxHighlighter.brushes.Xml = Brush; + + // CommonJS + typeof(exports) != 'undefined' ? exports.Brush = Brush : null; +})(); diff --git a/src/main/resources/src/webapp/scripts/shCore.js b/src/main/resources/src/webapp/scripts/shCore.js new file mode 100644 index 0000000..b47b645 --- /dev/null +++ b/src/main/resources/src/webapp/scripts/shCore.js @@ -0,0 +1,17 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('K M;I(M)1S 2U("2a\'t 4k M 4K 2g 3l 4G 4H");(6(){6 r(f,e){I(!M.1R(f))1S 3m("3s 15 4R");K a=f.1w;f=M(f.1m,t(f)+(e||""));I(a)f.1w={1m:a.1m,19:a.19?a.19.1a(0):N};H f}6 t(f){H(f.1J?"g":"")+(f.4s?"i":"")+(f.4p?"m":"")+(f.4v?"x":"")+(f.3n?"y":"")}6 B(f,e,a,b){K c=u.L,d,h,g;v=R;5K{O(;c--;){g=u[c];I(a&g.3r&&(!g.2p||g.2p.W(b))){g.2q.12=e;I((h=g.2q.X(f))&&h.P===e){d={3k:g.2b.W(b,h,a),1C:h};1N}}}}5v(i){1S i}5q{v=11}H d}6 p(f,e,a){I(3b.Z.1i)H f.1i(e,a);O(a=a||0;a-1},3d:6(g){e+=g}};c1&&p(e,"")>-1){a=15(J.1m,n.Q.W(t(J),"g",""));n.Q.W(f.1a(e.P),a,6(){O(K c=1;c<14.L-2;c++)I(14[c]===1d)e[c]=1d})}I(J.1w&&J.1w.19)O(K b=1;be.P&&J.12--}H e};I(!D)15.Z.1A=6(f){(f=n.X.W(J,f))&&J.1J&&!f[0].L&&J.12>f.P&&J.12--;H!!f};1r.Z.1C=6(f){M.1R(f)||(f=15(f));I(f.1J){K e=n.1C.1p(J,14);f.12=0;H e}H f.X(J)};1r.Z.Q=6(f,e){K a=M.1R(f),b,c;I(a&&1j e.58()==="3f"&&e.1i("${")===-1&&y)H n.Q.1p(J,14);I(a){I(f.1w)b=f.1w.19}Y f+="";I(1j e==="6")c=n.Q.W(J,f,6(){I(b){14[0]=1f 1r(14[0]);O(K d=0;dd.L-3;){i=1r.Z.1a.W(g,-1)+i;g=1Q.3i(g/10)}H(g?d[g]||"":"$")+i}Y{g=+i;I(g<=d.L-3)H d[g];g=b?p(b,i):-1;H g>-1?d[g+1]:h}})})}I(a&&f.1J)f.12=0;H c};1r.Z.1e=6(f,e){I(!M.1R(f))H n.1e.1p(J,14);K a=J+"",b=[],c=0,d,h;I(e===1d||+e<0)e=5D;Y{e=1Q.3i(+e);I(!e)H[]}O(f=M.3c(f);d=f.X(a);){I(f.12>c){b.U(a.1a(c,d.P));d.L>1&&d.P=e)1N}f.12===d.P&&f.12++}I(c===a.L){I(!n.1A.W(f,"")||h)b.U("")}Y b.U(a.1a(c));H b.L>e?b.1a(0,e):b};M.1h(/\\(\\?#[^)]*\\)/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"});M.1h(/\\((?!\\?)/,6(){J.19.U(N);H"("});M.1h(/\\(\\?<([$\\w]+)>/,6(f){J.19.U(f[1]);J.2N=R;H"("});M.1h(/\\\\k<([\\w$]+)>/,6(f){K e=p(J.19,f[1]);H e>-1?"\\\\"+(e+1)+(3R(f.2S.3a(f.P+f[0].L))?"":"(?:)"):f[0]});M.1h(/\\[\\^?]/,6(f){H f[0]==="[]"?"\\\\b\\\\B":"[\\\\s\\\\S]"});M.1h(/^\\(\\?([5A]+)\\)/,6(f){J.3d(f[1]);H""});M.1h(/(?:\\s+|#.*)+/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"},M.1B,6(){H J.2K("x")});M.1h(/\\./,6(){H"[\\\\s\\\\S]"},M.1B,6(){H J.2K("s")})})();1j 2e!="1d"&&(2e.M=M);K 1v=6(){6 r(a,b){a.1l.1i(b)!=-1||(a.1l+=" "+b)}6 t(a){H a.1i("3e")==0?a:"3e"+a}6 B(a){H e.1Y.2A[t(a)]}6 p(a,b,c){I(a==N)H N;K d=c!=R?a.3G:[a.2G],h={"#":"1c",".":"1l"}[b.1o(0,1)]||"3h",g,i;g=h!="3h"?b.1o(1):b.5u();I((a[h]||"").1i(g)!=-1)H a;O(a=0;d&&a\'+c+""});H a}6 n(a,b){a.1e("\\n");O(K c="",d=0;d<50;d++)c+=" ";H a=v(a,6(h){I(h.1i("\\t")==-1)H h;O(K g=0;(g=h.1i("\\t"))!=-1;)h=h.1o(0,g)+c.1o(0,b-g%b)+h.1o(g+1,h.L);H h})}6 x(a){H a.Q(/^\\s+|\\s+$/g,"")}6 D(a,b){I(a.Pb.P)H 1;Y I(a.Lb.L)H 1;H 0}6 y(a,b){6 c(k){H k[0]}O(K d=N,h=[],g=b.2D?b.2D:c;(d=b.1I.X(a))!=N;){K i=g(d,b);I(1j i=="3f")i=[1f e.2L(i,d.P,b.23)];h=h.1O(i)}H h}6 E(a){K b=/(.*)((&1G;|&1y;).*)/;H a.Q(e.3A.3M,6(c){K d="",h=N;I(h=b.X(c)){c=h[1];d=h[2]}H\'\'+c+""+d})}6 z(){O(K a=1E.36("1k"),b=[],c=0;c<1z 4I="1Z://2y.3L.3K/4L/5L"><3J><4N 1Z-4M="5G-5M" 6K="2O/1z; 6J=6I-8" /><1t>6L 1v<3B 1L="25-6M:6Q,6P,6O,6N-6F;6y-2f:#6x;2f:#6w;25-22:6v;2O-3D:3C;">1v3v 3.0.76 (72 73 3x)1Z://3u.2w/1v70 17 6U 71.6T 6X-3x 6Y 6D.6t 61 60 J 1k, 5Z 5R 5V <2R/>5U 5T 5S!\'}},1Y:{2j:N,2A:{}},1U:{},3A:{6n:/\\/\\*[\\s\\S]*?\\*\\//2c,6m:/\\/\\/.*$/2c,6l:/#.*$/2c,6k:/"([^\\\\"\\n]|\\\\.)*"/g,6o:/\'([^\\\\\'\\n]|\\\\.)*\'/g,6p:1f M(\'"([^\\\\\\\\"]|\\\\\\\\.)*"\',"3z"),6s:1f M("\'([^\\\\\\\\\']|\\\\\\\\.)*\'","3z"),6q:/(&1y;|<)!--[\\s\\S]*?--(&1G;|>)/2c,3M:/\\w+:\\/\\/[\\w-.\\/?%&=:@;]*/g,6a:{18:/(&1y;|<)\\?=?/g,1b:/\\?(&1G;|>)/g},69:{18:/(&1y;|<)%=?/g,1b:/%(&1G;|>)/g},6d:{18:/(&1y;|<)\\s*1k.*?(&1G;|>)/2T,1b:/(&1y;|<)\\/\\s*1k\\s*(&1G;|>)/2T}},16:{1H:6(a){6 b(i,k){H e.16.2o(i,k,e.13.1x[k])}O(K c=\'\',d=e.16.2x,h=d.2X,g=0;g";H c},2o:6(a,b,c){H\'<2W>\'+c+""},2b:6(a){K b=a.1F,c=b.1l||"";b=B(p(b,".20",R).1c);K d=6(h){H(h=15(h+"6f(\\\\w+)").X(c))?h[1]:N}("6g");b&&d&&e.16.2x[d].2B(b);a.3N()},2x:{2X:["21","2P"],21:{1H:6(a){I(a.V("2l")!=R)H"";K b=a.V("1t");H e.16.2o(a,"21",b?b:e.13.1x.21)},2B:6(a){a=1E.6j(t(a.1c));a.1l=a.1l.Q("47","")}},2P:{2B:6(){K a="68=0";a+=", 18="+(31.30-33)/2+", 32="+(31.2Z-2Y)/2+", 30=33, 2Z=2Y";a=a.Q(/^,/,"");a=1P.6Z("","38",a);a.2C();K b=a.1E;b.6W(e.13.1x.37);b.6V();a.2C()}}}},35:6(a,b){K c;I(b)c=[b];Y{c=1E.36(e.13.34);O(K d=[],h=0;h(.*?))\\\\]$"),s=1f M("(?<27>[\\\\w-]+)\\\\s*:\\\\s*(?<1T>[\\\\w-%#]+|\\\\[.*?\\\\]|\\".*?\\"|\'.*?\')\\\\s*;?","g");(j=s.X(k))!=N;){K o=j.1T.Q(/^[\'"]|[\'"]$/g,"");I(o!=N&&m.1A(o)){o=m.X(o);o=o.2V.L>0?o.2V.1e(/\\s*,\\s*/):[]}l[j.27]=o}g={1F:g,1n:C(i,l)};g.1n.1D!=N&&d.U(g)}H d},1M:6(a,b){K c=J.35(a,b),d=N,h=e.13;I(c.L!==0)O(K g=0;g")==o-3){m=m.4h(0,o-3);s=R}l=s?m:l}I((i.1t||"")!="")k.1t=i.1t;k.1D=j;d.2Q(k);b=d.2F(l);I((i.1c||"")!="")b.1c=i.1c;i.2G.74(b,i)}}},2E:6(a){w(1P,"4k",6(){e.1M(a)})}};e.2E=e.2E;e.1M=e.1M;e.2L=6(a,b,c){J.1T=a;J.P=b;J.L=a.L;J.23=c;J.1V=N};e.2L.Z.1q=6(){H J.1T};e.4l=6(a){6 b(j,l){O(K m=0;md)1N;Y I(g.P==c.P&&g.L>c.L)a[b]=N;Y I(g.P>=c.P&&g.P\'+c+""},3Q:6(a,b){K c="",d=a.1e("\\n").L,h=2u(J.V("2i-1s")),g=J.V("2z-1s-2t");I(g==R)g=(h+d-1).1q().L;Y I(3R(g)==R)g=0;O(K i=0;i\'+j+"":"")+i)}H a},4f:6(a){H a?"<4a>"+a+"":""},4b:6(a,b){6 c(l){H(l=l?l.1V||g:g)?l+" ":""}O(K d=0,h="",g=J.V("1D",""),i=0;i|&1y;2R\\s*\\/?&1G;/2T;I(e.13.46==R)b=b.Q(h,"\\n");I(e.13.44==R)b=b.Q(h,"");b=b.1e("\\n");h=/^\\s*/;g=4Q;O(K i=0;i0;i++){K k=b[i];I(x(k).L!=0){k=h.X(k);I(k==N){a=a;1N a}g=1Q.4q(k[0].L,g)}}I(g>0)O(i=0;i\'+(J.V("16")?e.16.1H(J):"")+\'<3Z 5z="0" 5H="0" 5J="0">\'+J.4f(J.V("1t"))+"<3T><3P>"+(1u?\'<2d 1g="1u">\'+J.3Q(a)+"":"")+\'<2d 1g="17">\'+b+""},2F:6(a){I(a===N)a="";J.17=a;K b=J.3Y("T");b.3X=J.1H(a);J.V("16")&&w(p(b,".16"),"5c",e.16.2b);J.V("3V-17")&&w(p(b,".17"),"56",f);H b},2Q:6(a){J.1c=""+1Q.5d(1Q.5n()*5k).1q();e.1Y.2A[t(J.1c)]=J;J.1n=C(e.2v,a||{});I(J.V("2k")==R)J.1n.16=J.1n.1u=11},5j:6(a){a=a.Q(/^\\s+|\\s+$/g,"").Q(/\\s+/g,"|");H"\\\\b(?:"+a+")\\\\b"},5f:6(a){J.28={18:{1I:a.18,23:"1k"},1b:{1I:a.1b,23:"1k"},17:1f M("(?<18>"+a.18.1m+")(?<17>.*?)(?<1b>"+a.1b.1m+")","5o")}}};H e}();1j 2e!="1d"&&(2e.1v=1v);',62,441,'||||||function|||||||||||||||||||||||||||||||||||||return|if|this|var|length|XRegExp|null|for|index|replace|true||div|push|getParam|call|exec|else|prototype||false|lastIndex|config|arguments|RegExp|toolbar|code|left|captureNames|slice|right|id|undefined|split|new|class|addToken|indexOf|typeof|script|className|source|params|substr|apply|toString|String|line|title|gutter|SyntaxHighlighter|_xregexp|strings|lt|html|test|OUTSIDE_CLASS|match|brush|document|target|gt|getHtml|regex|global|join|style|highlight|break|concat|window|Math|isRegExp|throw|value|brushes|brushName|space|alert|vars|http|syntaxhighlighter|expandSource|size|css|case|font|Fa|name|htmlScript|dA|can|handler|gm|td|exports|color|in|href|first|discoveredBrushes|light|collapse|object|cache|getButtonHtml|trigger|pattern|getLineHtml|nbsp|numbers|parseInt|defaults|com|items|www|pad|highlighters|execute|focus|func|all|getDiv|parentNode|navigator|INSIDE_CLASS|regexList|hasFlag|Match|useScriptTags|hasNamedCapture|text|help|init|br|input|gi|Error|values|span|list|250|height|width|screen|top|500|tagName|findElements|getElementsByTagName|aboutDialog|_blank|appendChild|charAt|Array|copyAsGlobal|setFlag|highlighter_|string|attachEvent|nodeName|floor|backref|output|the|TypeError|sticky|Za|iterate|freezeTokens|scope|type|textarea|alexgorbatchev|version|margin|2010|005896|gs|regexLib|body|center|align|noBrush|require|childNodes|DTD|xhtml1|head|org|w3|url|preventDefault|container|tr|getLineNumbersHtml|isNaN|userAgent|tbody|isLineHighlighted|quick|void|innerHTML|create|table|links|auto|smart|tab|stripBrs|tabs|bloggerMode|collapsed|plain|getCodeLinesHtml|caption|getMatchesHtml|findMatches|figureOutLineNumbers|removeNestedMatches|getTitleHtml|brushNotHtmlScript|substring|createElement|Highlighter|load|HtmlScript|Brush|pre|expand|multiline|min|Can|ignoreCase|find|blur|extended|toLowerCase|aliases|addEventListener|innerText|textContent|wasn|select|createTextNode|removeChild|option|same|frame|xmlns|dtd|twice|1999|equiv|meta|htmlscript|transitional|1E3|expected|PUBLIC|DOCTYPE|on|W3C|XHTML|TR|EN|Transitional||configured|srcElement|Object|after|run|dblclick|matchChain|valueOf|constructor|default|switch|click|round|execAt|forHtmlScript|token|gimy|functions|getKeywords|1E6|escape|within|random|sgi|another|finally|supply|MSIE|ie|toUpperCase|catch|returnValue|definition|event|border|imsx|constructing|one|Infinity|from|when|Content|cellpadding|flags|cellspacing|try|xhtml|Type|spaces|2930402|hosted_button_id|lastIndexOf|donate|active|development|keep|to|xclick|_s|Xml|please|like|you|paypal|cgi|cmd|webscr|bin|highlighted|scrollbars|aspScriptTags|phpScriptTags|sort|max|scriptScriptTags|toolbar_item|_|command|command_|number|getElementById|doubleQuotedString|singleLinePerlComments|singleLineCComments|multiLineCComments|singleQuotedString|multiLineDoubleQuotedString|xmlComments|alt|multiLineSingleQuotedString|If|https|1em|000|fff|background|5em|xx|bottom|75em|Gorbatchev|large|serif|CDATA|continue|utf|charset|content|About|family|sans|Helvetica|Arial|Geneva|3em|nogutter|Copyright|syntax|close|write|2004|Alex|open|JavaScript|highlighter|July|02|replaceChild|offset|83'.split('|'),0,{})) diff --git a/src/main/resources/src/webapp/security.html b/src/main/resources/src/webapp/security.html new file mode 100644 index 0000000..19ad1df --- /dev/null +++ b/src/main/resources/src/webapp/security.html @@ -0,0 +1,68 @@ + + + + + Security + + +
+
+ + + Lift based web apps have a lot of security baked + right in. Lift apps are resistant to many common + security vulnerabilities. + + +
+ +
+ + + Here are Lift's built-in safeguards to combat + many of the + OWASP Top 10 vulnerabilities: +
    +
  • A1: Injection - Lift's Mapper and Record do proper + escaping of query strings before they are sent to the + backing store.
  • +
  • A2: XSS - Lift keeps the rendered page as a DOM + until very late in the page rendering cycle. This allows + Lift to automatically HTML escape Strings before they + are sent to the browser.
  • +
  • A3: Session Management - Lift uses the J/EE container's + session management, allows for generation of new sessions + on login, and keeps passwords hashed at all times with + per-row salt.
  • +
  • A4: Direct Object References - Lift forms do + not expose direct object references, but instead keep + the object references server-side and issues a session-specific + token that refers to the objects.
  • +
  • A5: CSRF - Lift uses session-specific bindings between + HTML elements and the server-side behaviors associated + with those elements. The bindings cannot be predicted + so it's not possible to issue Cross Site requests that + invoke session-specific bindings.
  • +
  • A8: URL Access - Lift includes SiteMap which provides declarative + rules for access to URLs in the application. + SiteMap will deny access to URLs unless the criteria + is met for accessing the specific URL.
  • +
+
+
+
+ +
+ + + Because Lift apps are more secure by default, + developers can focus their development efforts on + features rather than writing ad hoc defenses + to the OWASP Top 10 and other vulnerabilities. + + +
+ +
+ + diff --git a/src/main/resources/src/webapp/static/index.html b/src/main/resources/src/webapp/static/index.html new file mode 100644 index 0000000..9529015 --- /dev/null +++ b/src/main/resources/src/webapp/static/index.html @@ -0,0 +1,5 @@ +
+ Static content... everything you put in the /static + directory will be served without additions to SiteMap +
+ diff --git a/src/main/resources/src/webapp/templates-hidden/default.html b/src/main/resources/src/webapp/templates-hidden/default.html new file mode 100644 index 0000000..b426994 --- /dev/null +++ b/src/main/resources/src/webapp/templates-hidden/default.html @@ -0,0 +1,127 @@ + + + + + + Seven Things: + + + + + + + + + + + + + + + + + + +
+
+

Seven Things

+
+ +
+ + + +
+
The main content will get bound here
+
+ +
+
+

+ Lift + is Copyright 2007-2011 WorldWide Conferencing, LLC. + Distributed under an Apache 2.0 License.

+
+
+ + + diff --git a/src/main/resources/src/webapp/templates-hidden/wizard-all.html b/src/main/resources/src/webapp/templates-hidden/wizard-all.html new file mode 100644 index 0000000..e1ea727 --- /dev/null +++ b/src/main/resources/src/webapp/templates-hidden/wizard-all.html @@ -0,0 +1,57 @@ +
+
Page of
+
+
+
+
+ + + + + + + + +
+ + + + + + + + + +
    + +
  • + +
  • +
    +
+
+
+ +
+
+
+
+ + + + + + +
+ + + + + +
+
+
+
+
diff --git a/src/main/resources/src/webapp/templates.html b/src/main/resources/src/webapp/templates.html new file mode 100644 index 0000000..8a914fe --- /dev/null +++ b/src/main/resources/src/webapp/templates.html @@ -0,0 +1,62 @@ + + + + + Designer Friendly Templates + + + + + +
+
+ + + Lift supports designer friendly templates. + This means that all templates... all pages + on your site can be valid Html5 or XHTML. + Your designers can edit the same pages that + your developers edit. The designers do not + have to learn any tag libraries or any other + language. The dynamic content is based on + Lift's snippets and the snippet invocation + is done via specially css class names. + Here's the source for this page: + + +
+ + +
view code
+ +
+ + + The benefits to your team include: +
    +
  • A single place for all your team members + to keep their code
  • +
  • No need for developers to "shred" the + pages designers give them or otherwise + keep pages in sync
  • +
  • Pages can always be validated
  • +
  • No additional learning for the designers
  • +
+
+
+
+ +
+ + diff --git a/src/main/resources/src/webapp/wiring.html b/src/main/resources/src/webapp/wiring.html new file mode 100644 index 0000000..44ae9e3 --- /dev/null +++ b/src/main/resources/src/webapp/wiring.html @@ -0,0 +1,105 @@ + + + + + Wiring + + +
+
+ + + As web pages get more complex, there are a lot + of interdependent items displayed on the page. For + example, you may have a list of invitations along + with a count of invitations. As you accept or + reject each invitation (assuming this is done via + Ajax), you want the invation count to be automatically + updated. Lift's Wiring allows you to declare relationships + among the various elements on a page and when any of the + precedent elements change, the dependent items + are redisplayed on the next HTTP response (Ajax or Comet). + + +
+ +
+ +
+ + + Those are a lot of words. Let's see how we can + build an invoice screen + + +
+ + +
+
input goes here
+
+ +
+ +
Subtotal: subtotal
+ +
Tax Rate:
+ +
Taxable: taxable
+ +
Tax: Tax
+ +
Total: Total
+
+ + + + + Let's take a look at the markup for the + invoice + + +
view code
+ +
+ + + Each of the items on the screen that need to be automatically + updates is declared as a snippet. And the snippet implementation + for each wired element is simple as well: + + +
+ +
view code
+ + +
+ + + Finally, we declare the relationship among the elements + (or cells in Wiring-speak): + + +
+ +
view code
+ +
+ +
+ + + Using Wiring, you can create very complex + inter-relationships with the elements on the + screen. When one is updated, all the dependent + elements update automatically. + This is a tremendous time-saver and makes maintaining + your site much easier because the maintainer doesn't + have to know all the dependencies. + + +
+
+ + diff --git a/src/main/resources/src/webapp/wizard.html b/src/main/resources/src/webapp/wizard.html new file mode 100644 index 0000000..526d74b --- /dev/null +++ b/src/main/resources/src/webapp/wizard.html @@ -0,0 +1,77 @@ + + + + + Wizard + + +
+
+ + + Lift's Wizard allows you to define + multi-page input screens with field and + form level validation that can be run + either as normal HTTP forms (with full back- + button support) or as Ajax. + + +
+ +
+
+
+ +
+ +
+ Run the wizard as Ajax: + +
+ +
+ +
+ + + The source for the wizard: + + +
+ + +
view code
+ +
+ +
+ + + Wizard offers functionality similar to JBoss + Seam. However, Wizard purely declarative code + rather than Java + XML. Further, all Wizard + fields are type safe. For example, the age field + is an Int, so you can multiply the age by 3 + without explicit casting. + + +
+ +
+ +
+ + + Wizard allows you to model complex user inputs... + super-forms... declaratively so that the logic + is obvious and the maintainence is simple. + + +
+ + + + +
+ + diff --git a/src/main/scala/net/liftweb/seventhings/lib/HelpersJBridge.scala b/src/main/scala/net/liftweb/seventhings/lib/HelpersJBridge.scala new file mode 100644 index 0000000..1de6518 --- /dev/null +++ b/src/main/scala/net/liftweb/seventhings/lib/HelpersJBridge.scala @@ -0,0 +1,14 @@ +package net.liftweb.seventhings.lib + +import net.liftweb.util._ + +/** + * I was not able to just return the Helpers object. the compiler complained it found Helpers$ instead of Helpers. + */ +class HelpersJBridge extends TimeHelpers with StringHelpers with ListHelpers +with SecurityHelpers with BindHelpers with HttpHelpers +with IoHelpers with BasicTypesHelpers +with ClassHelpers with ControlHelpers +{ + +} \ No newline at end of file diff --git a/src/main/scala/net/liftweb/seventhings/lib/WizardJ.scala b/src/main/scala/net/liftweb/seventhings/lib/WizardJ.scala index cd23b26..c15b15a 100644 --- a/src/main/scala/net/liftweb/seventhings/lib/WizardJ.scala +++ b/src/main/scala/net/liftweb/seventhings/lib/WizardJ.scala @@ -5,6 +5,17 @@ import net.liftweb.wizard.Wizard abstract class WizardJ extends Wizard { - abstract class ScreenJ extends Screen + abstract class ScreenJ extends Screen { + + /* + protected def field[T](underlying: => BaseField{type ValueType=T}, + stuff: FilterOrValidate[T]*)(implicit man: Manifest[T]): Field{type ValueType=T} = { + + */ + // field(java.lang.String,java.lang.String,scala.Function1>,scala.Function1>) + + def fieldj(s1: String, arg2: scala.Function1[java.lang.String, scala.collection.immutable.List[net.liftweb.util.FieldError]]*) = field(s1, arg2) + + } } \ No newline at end of file diff --git a/src/main/scala/net/liftweb/seventhings/snippet/MyWizardScala.scala b/src/main/scala/net/liftweb/seventhings/snippet/MyWizardScala.scala new file mode 100644 index 0000000..3d2db25 --- /dev/null +++ b/src/main/scala/net/liftweb/seventhings/snippet/MyWizardScala.scala @@ -0,0 +1,64 @@ +package net.liftweb.seventhings +package snippet + +import net.liftweb._ +import http._ +import js.jquery.JqJsCmds._ +import util.Func0 +import wizard._ +import util.Helpers._ +import lib.WizardJ + +/** + * An example of a wizard in Lift + */ +class MyWizardScala extends Wizard { + + // define the first screen + class NameAndAgeScreen extends Screen { + // it has a name field + val name = field(S ? "First Name", "", + valMinLen(2, S ? "Name Too Short"), + valMaxLen(40, S ? "Name Too Long")) + + // and an age field + val age = field(S ? "Age", 0, minVal(5, S ?? "Too young"), + maxVal(120, S ? "You should be dead")) + + // choose the next screen based on the age + override def nextScreen = if (age.is < 18) parentName else favoritePet + } + + // We ask the parent's name if the person is under 18 + class ParentNameScreen extends Screen { + val parentName = field(S ? "Mom or Dad's name", "", + valMinLen(2, S ? "Name Too Short"), + valMaxLen(40, S ? "Name Too Long")) + } + + // we ask for the favorite pet + class FavoritePetScreen extends Screen { + val petName = field(S ? "Pet's name", "", + valMinLen(2, S ? "Name Too Short"), + valMaxLen(40, S ? "Name Too Long")) + } + + // what to do on completion of the wizard + def finish() { + S.notice("Thank you for registering your pet: "+ + favoritePet.petName+ + " your age * 3: "+nameAndAge.age * 3) + } + + val nameAndAge = new NameAndAgeScreen + val parentName = new ParentNameScreen + val favoritePet = new FavoritePetScreen + + def getNameAndAge = nameAndAge + + def getParentName = parentName + + def getFavoritePet = favoritePet + +} +