diff options
author | Li Haoyi <haoyi@dropbox.com> | 2014-12-28 18:30:51 +0100 |
---|---|---|
committer | Li Haoyi <haoyi@dropbox.com> | 2014-12-28 18:30:51 +0100 |
commit | e27f2ba244d0fef1a654da99d8c8a36cfef5a61a (patch) | |
tree | 1c025b74acec6ea48f287b0d06186eaa2fbe5a71 | |
parent | 47495632fb60bb6bdc4b61b3e00333dbe1182e7b (diff) | |
parent | a10f9f097944a2586d2d98fc09a3e43bb77d0250 (diff) | |
download | hands-on-scala-js-e27f2ba244d0fef1a654da99d8c8a36cfef5a61a.tar.gz hands-on-scala-js-e27f2ba244d0fef1a654da99d8c8a36cfef5a61a.tar.bz2 hands-on-scala-js-e27f2ba244d0fef1a654da99d8c8a36cfef5a61a.zip |
merged
13 files changed, 157 insertions, 4 deletions
diff --git a/book/src/main/scalatex/book/handson/GettingStarted.scalatex b/book/src/main/scalatex/book/handson/GettingStarted.scalatex index a32ba9e..d2486c2 100644 --- a/book/src/main/scalatex/book/handson/GettingStarted.scalatex +++ b/book/src/main/scalatex/book/handson/GettingStarted.scalatex @@ -320,7 +320,7 @@ @li The @lnk.dom.CanvasRenderingContext2D has a bunch of methods on it that can be used to draw things. Here we only draw 1x1 rectangles to put points on the canvas; try modifying the code to make it draw something else. @li - We've look at the @code{master} branch of @code{workbench-example-app}, but this project also has several other branches showing off different facets of Scala.js: @lnk("dodge-the-dots", "https://github.com/lihaoyi/workbench-example-app/tree/dodge-the-dots") and @lnk("space-invaders", "https://github.com/lihaoyi/workbench-example-app/tree/space-invaders") are both interesting branches worth playing with as a beginner. Check them out! + We've looked at the @code{master} branch of @code{workbench-example-app}, but this project also has several other branches showing off different facets of Scala.js: @lnk("dodge-the-dots", "https://github.com/lihaoyi/workbench-example-app/tree/dodge-the-dots") and @lnk("space-invaders", "https://github.com/lihaoyi/workbench-example-app/tree/space-invaders") are both interesting branches worth playing with as a beginner. Check them out! @li Try publishing the output code somewhere. You only need @code{example-opt.js} and @code{index-opt.html}; try putting them somewhere online where the world can see it. diff --git a/book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex b/book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex index d49728f..98dccc2 100644 --- a/book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex +++ b/book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex @@ -76,7 +76,7 @@ Scalatags requires that anything you want to embed in a Scalatags fragment be implicitly convertible to @hl.scala{Frag}; here we are providing one for any Scala.Rx @hl.scala{Rx[T]}s, as long as the @hl.scala{T} provided is itself convertible to a @hl.scala{Frag}. We call @hl.scala{r().render} to extract the "current" value of the @hl.scala{Rx}, and then set up an @hl.scala{Obs} that watches the @hl.scala{Rx}, replacing the previous value with the current one every time its value changes. @p - Now that the set-up is out of the way, let's consider a simple HTML widhet that lets you enter text in a @hl.html{<textarea>}, and keeps track of the number of words, characters, and counts how long each word is. + Now that the set-up is out of the way, let's consider a simple HTML widget that lets you enter text in a @hl.html{<textarea>}, and keeps track of the number of words, characters, and counts how long each word is. @split @more @@ -284,7 +284,7 @@ @example(canvas, "Async().main") @p - We have an @hl.scala{async} block, which contains a while loop. Each round around the loop, we wait for the @hl.scala{mousedown} channel to start the path, waiting for either @hl.scala{mousedown} or @hl.scala{mousedown} (which continues the path or ends it respectively), fill the shape, and then wait for another @hl.scala{mousedown} before clearing the canvas and going again. + We have an @hl.scala{async} block, which contains a while loop. Each round around the loop, we wait for the @hl.scala{mousedown} channel to start the path, waiting for either @hl.scala{mousemove} or @hl.scala{mouseup} (which continues the path or ends it respectively), fill the shape, and then wait for another @hl.scala{mousedown} before clearing the canvas and going again. @p Hopefully you'd agree that this code is much simpler to read and understand than the previous version. In particular, the control-flow of the code goes from top to bottom in a "natural" fashion, rather than jumping around ad-hoc like in the previous callback-based design. diff --git a/book/src/main/scalatex/book/indepth/SemanticDifferences.scalatex b/book/src/main/scalatex/book/indepth/SemanticDifferences.scalatex index ebfd1db..96f3929 100644 --- a/book/src/main/scalatex/book/indepth/SemanticDifferences.scalatex +++ b/book/src/main/scalatex/book/indepth/SemanticDifferences.scalatex @@ -1,6 +1,6 @@ @import BookData._ @p - Although Scala.js tries very hard to maintain compatibility with Scala-JVM, there are some parts where the two platforms differs. This can be roughly grouped into two things: differences in the libraries available,and differences in the language itself. This chapter will cover both of these facets. + Although Scala.js tries very hard to maintain compatibility with Scala-JVM, there are some parts where the two platforms differs. This can be roughly grouped into two things: differences in the libraries available, and differences in the language itself. This chapter will cover both of these facets. @sect{Language Differences} @sect{Floats are Doubles} diff --git a/examples/crossBuilds/clientserver b/examples/crossBuilds/clientserver deleted file mode 160000 -Subproject 8d199942e6ad4c927b825c493c69067d9474a8f diff --git a/examples/crossBuilds/clientserver/Procfile b/examples/crossBuilds/clientserver/Procfile new file mode 100644 index 0000000..59ff8a8 --- /dev/null +++ b/examples/crossBuilds/clientserver/Procfile @@ -0,0 +1 @@ +web: server/target/universal/stage/bin/server diff --git a/examples/crossBuilds/clientserver/build.sbt b/examples/crossBuilds/clientserver/build.sbt new file mode 100644 index 0000000..048df8a --- /dev/null +++ b/examples/crossBuilds/clientserver/build.sbt @@ -0,0 +1,38 @@ +import NativePackagerKeys._ +import utest.jsrunner.JsCrossBuild +import scalajs.sbtplugin.ScalaJSPlugin._ +import ScalaJSKeys._ +val sharedSettings = Seq( + unmanagedSourceDirectories in Compile += + baseDirectory.value / "shared" / "main" / "scala", + libraryDependencies ++= Seq( + "com.scalatags" %%% "scalatags" % "0.4.2", + "com.lihaoyi" %%% "upickle" % "0.2.5" + ), + scalaVersion := "2.11.4" +) + +lazy val client = project.in(file("client")) + .settings(scalaJSSettings:_*) + .settings(sharedSettings:_*) + .settings( + libraryDependencies ++= Seq( + "org.scala-lang.modules.scalajs" %%% "scalajs-dom" % "0.6" + ) +) + +lazy val server = project.in(file("server")) + .settings(sharedSettings:_*) + .settings(packageArchetype.java_application:_*) + .settings( + libraryDependencies ++= Seq( + "io.spray" %% "spray-can" % "1.3.2", + "io.spray" %% "spray-routing" % "1.3.2", + "com.typesafe.akka" %% "akka-actor" % "2.3.6" + ), + (resources in Compile) += { + (fastOptJS in (client, Compile)).value + (artifactPath in (client, Compile, fastOptJS)).value + } +) + diff --git a/examples/crossBuilds/clientserver/client/shared/main/scala/simple/FileData.scala b/examples/crossBuilds/clientserver/client/shared/main/scala/simple/FileData.scala new file mode 100644 index 0000000..d3d2f91 --- /dev/null +++ b/examples/crossBuilds/clientserver/client/shared/main/scala/simple/FileData.scala @@ -0,0 +1,3 @@ +package simple + +case class FileData(name: String, size: Long)
\ No newline at end of file diff --git a/examples/crossBuilds/clientserver/client/src/main/scala/simple/Client.scala b/examples/crossBuilds/clientserver/client/src/main/scala/simple/Client.scala new file mode 100644 index 0000000..9b3eda1 --- /dev/null +++ b/examples/crossBuilds/clientserver/client/src/main/scala/simple/Client.scala @@ -0,0 +1,36 @@ +package simple + +import scalatags.JsDom.all._ +import scalajs.concurrent.JSExecutionContext.Implicits.runNow +import org.scalajs.dom +import dom.extensions.Ajax +import scalajs.js.annotation.JSExport + +@JSExport +object Client extends{ + @JSExport + def main(container: dom.HTMLDivElement) = { + val inputBox = input.render + val outputBox = ul.render + def update() = Ajax.post("/ajax/list", inputBox.value).foreach{ xhr => + val data = upickle.read[Seq[FileData]](xhr.responseText) + outputBox.innerHTML = "" + for(FileData(name, size) <- data){ + outputBox.appendChild( + li( + b(name), " - ", size, " bytes" + ).render + ) + } + } + inputBox.onkeyup = (e: dom.Event) => update() + update() + container.appendChild( + div( + h1("File Search"), + inputBox, + outputBox + ).render + ) + } +}
\ No newline at end of file diff --git a/examples/crossBuilds/clientserver/project/build.properties b/examples/crossBuilds/clientserver/project/build.properties new file mode 100644 index 0000000..748703f --- /dev/null +++ b/examples/crossBuilds/clientserver/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.7 diff --git a/examples/crossBuilds/clientserver/project/build.sbt b/examples/crossBuilds/clientserver/project/build.sbt new file mode 100644 index 0000000..c24e2b0 --- /dev/null +++ b/examples/crossBuilds/clientserver/project/build.sbt @@ -0,0 +1,6 @@ +/*project/build.sbt*/ +addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % "0.5.5") + +addSbtPlugin("com.lihaoyi" % "utest-js-plugin" % "0.2.4") + +addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "0.7.4") diff --git a/examples/crossBuilds/clientserver/server/shared b/examples/crossBuilds/clientserver/server/shared new file mode 120000 index 0000000..f32be42 --- /dev/null +++ b/examples/crossBuilds/clientserver/server/shared @@ -0,0 +1 @@ +../client/shared
\ No newline at end of file diff --git a/examples/crossBuilds/clientserver/server/src/main/scala/simple/Page.scala b/examples/crossBuilds/clientserver/server/src/main/scala/simple/Page.scala new file mode 100644 index 0000000..d657290 --- /dev/null +++ b/examples/crossBuilds/clientserver/server/src/main/scala/simple/Page.scala @@ -0,0 +1,21 @@ +package simple +import scalatags.Text.all._ + +object Page{ + val boot = + "Client().main(document.getElementById('contents'))" + val skeleton = + html( + head( + script(src:="/client-fastopt.js"), + link( + rel:="stylesheet", + href:="https://cdnjs.cloudflare.com/ajax/libs/pure/0.5.0/pure-min.css" + ) + ), + body( + onload:=boot, + div(id:="contents") + ) + ) +} diff --git a/examples/crossBuilds/clientserver/server/src/main/scala/simple/Server.scala b/examples/crossBuilds/clientserver/server/src/main/scala/simple/Server.scala new file mode 100644 index 0000000..e9038b5 --- /dev/null +++ b/examples/crossBuilds/clientserver/server/src/main/scala/simple/Server.scala @@ -0,0 +1,46 @@ +package simple + +import akka.actor.ActorSystem +import spray.http.{HttpEntity, MediaTypes} +import spray.routing.SimpleRoutingApp + +import scala.util.Properties + +object Server extends SimpleRoutingApp{ + def main(args: Array[String]): Unit = { + implicit val system = ActorSystem() + val port = Properties.envOrElse("PORT", "8080").toInt + startServer("0.0.0.0", port = port){ + get{ + pathSingleSlash{ + complete{ + HttpEntity( + MediaTypes.`text/html`, + Page.skeleton.render + ) + } + } ~ + getFromResourceDirectory("") + } ~ + post{ + path("ajax" / "list"){ + extract(_.request.entity.asString) { e => + complete { + upickle.write(list(e)) + } + } + } + } + } + } + def list(path: String) = { + val (dir, last) = path.splitAt(path.lastIndexOf("/") + 1) + val files = + Option(new java.io.File("./" + dir).listFiles()) + .toSeq.flatten + for{ + f <- files + if f.getName.startsWith(last) + } yield FileData(f.getName, f.length()) + } +}
\ No newline at end of file |