summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi@dropbox.com>2014-11-02 04:57:37 -0800
committerLi Haoyi <haoyi@dropbox.com>2014-11-02 04:57:37 -0800
commita33254276bd211bf33be86eeb871ddbfe36fdb47 (patch)
treeb257d473be4fa110f7846f372ea94fc6714dad90
parentd00a2e25a9ee527fa39feb04c3137715501e9fda (diff)
downloadhands-on-scala-js-a33254276bd211bf33be86eeb871ddbfe36fdb47.tar.gz
hands-on-scala-js-a33254276bd211bf33be86eeb871ddbfe36fdb47.tar.bz2
hands-on-scala-js-a33254276bd211bf33be86eeb871ddbfe36fdb47.zip
Moved `examples` into `examples/demos`, sketched out a simple example cross-module
-rw-r--r--book/src/main/scala/book/Utils.scala24
-rw-r--r--book/src/main/scalatex/book/Index.scalatex43
-rw-r--r--book/src/main/scalatex/book/Intro.scalatex2
-rw-r--r--book/src/main/scalatex/book/handson/CanvasApp.scalatex18
-rw-r--r--book/src/main/scalatex/book/handson/CrossModules.scalatex17
-rw-r--r--book/src/main/scalatex/book/handson/WebPage.scalatex34
-rw-r--r--build.sbt8
-rw-r--r--examples/crossBuilds/simple/build.sbt8
-rw-r--r--examples/crossBuilds/simple/js/src/main/scala/simple/Platform.scala18
-rw-r--r--examples/crossBuilds/simple/jvm/src/main/scala/simple/Platform.scala23
-rw-r--r--examples/crossBuilds/simple/project/build.sbt1
-rw-r--r--examples/crossBuilds/simple/shared/main/scala/simple/Simple.scala9
-rw-r--r--examples/demos/build.sbt (renamed from examples/build.sbt)0
-rw-r--r--examples/demos/src/main/resources/webpage/weather.js (renamed from examples/src/main/resources/webpage/weather.js)0
-rw-r--r--examples/demos/src/main/scala/Splash.scala (renamed from examples/src/main/scala/Splash.scala)0
-rw-r--r--examples/demos/src/main/scala/canvasapp/Clock.scala (renamed from examples/src/main/scala/canvasapp/Clock.scala)0
-rw-r--r--examples/demos/src/main/scala/canvasapp/FlappyLine.scala (renamed from examples/src/main/scala/canvasapp/FlappyLine.scala)0
-rw-r--r--examples/demos/src/main/scala/canvasapp/ScratchPad.scala (renamed from examples/src/main/scala/canvasapp/ScratchPad.scala)0
-rw-r--r--examples/demos/src/main/scala/webpage/HelloWorld0.scala (renamed from examples/src/main/scala/webpage/HelloWorld0.scala)0
-rw-r--r--examples/demos/src/main/scala/webpage/HelloWorld1.scala (renamed from examples/src/main/scala/webpage/HelloWorld1.scala)0
-rw-r--r--examples/demos/src/main/scala/webpage/Inputs.scala (renamed from examples/src/main/scala/webpage/Inputs.scala)0
-rw-r--r--examples/demos/src/main/scala/webpage/Search0.scala (renamed from examples/src/main/scala/webpage/Search0.scala)0
-rw-r--r--examples/demos/src/main/scala/webpage/Search1.scala (renamed from examples/src/main/scala/webpage/Search1.scala)0
-rw-r--r--examples/demos/src/main/scala/webpage/Weather0.scala (renamed from examples/src/main/scala/webpage/Weather0.scala)0
-rw-r--r--examples/demos/src/main/scala/webpage/Weather1.scala (renamed from examples/src/main/scala/webpage/Weather1.scala)0
-rw-r--r--examples/demos/src/main/scala/webpage/Weather2.scala (renamed from examples/src/main/scala/webpage/Weather2.scala)0
-rw-r--r--examples/demos/src/main/scala/webpage/Weather3.scala (renamed from examples/src/main/scala/webpage/Weather3.scala)0
-rw-r--r--examples/demos/src/main/scala/webpage/WeatherSearch.scala (renamed from examples/src/main/scala/webpage/WeatherSearch.scala)0
-rw-r--r--project/build.sbt1
29 files changed, 139 insertions, 67 deletions
diff --git a/book/src/main/scala/book/Utils.scala b/book/src/main/scala/book/Utils.scala
index 690cee1..d5272a6 100644
--- a/book/src/main/scala/book/Utils.scala
+++ b/book/src/main/scala/book/Utils.scala
@@ -44,25 +44,25 @@ object Utils{
var indent = 0
- val headers = Seq[(String => scalatags.Text.Tag, Option[Frag => Frag])](
- (h => div(cls:="header")(
+ val headers = Seq[((String, String) => scalatags.Text.Tag, Option[Frag => Frag])](
+ ((h, s) => div(cls:="header")(
h1(h),
- h2("Writing client-side web applications in Scala")
+ h2(s)
), Some(f => div(cls:="content", f))),
- (h => div(cls:="header")(
+ ((h, s) => div(cls:="header")(
h1(id:=Utils.munge(h), h),
br
), None),
- (h1(_), None),
- (h2(_), None),
- (h3(_), None),
- (h4(_), None),
- (h5(_), None),
- (h6(_), None)
+ (h1(_, _), None),
+ (h2(_, _), None),
+ (h3(_, _), None),
+ (h4(_, _), None),
+ (h5(_, _), None),
+ (h6(_, _), None)
)
var structure: Node = null
- case class sect(name: String){
+ case class sect(name: String, subname: String = ""){
indent += 1
val newNode = Node(name, mutable.Buffer.empty)
val (headerWrap, contentWrap) = headers(indent-1)
@@ -72,7 +72,7 @@ object Utils{
def apply(args: Frag*) = {
val wrappedContents = contentWrap.getOrElse((x: Frag) => x)(args)
val res = Seq[Frag](
- headerWrap(name)(cls:="content-subhead", id:=munge(name)),
+ headerWrap(name, subname)(cls:="content-subhead", id:=munge(name)),
wrappedContents
)
indent -= 1
diff --git a/book/src/main/scalatex/book/Index.scalatex b/book/src/main/scalatex/book/Index.scalatex
index a3c77f6..0ff807d 100644
--- a/book/src/main/scalatex/book/Index.scalatex
+++ b/book/src/main/scalatex/book/Index.scalatex
@@ -1,8 +1,8 @@
-@sect("Hands-on Scala.js")
+@sect("Hands-on Scala.js", "Writing client-side web applications in Scala")
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/Splash.scala", "var x")
+ @hl.ref("examples/demos/src/main/scala/Splash.scala", "var x")
@div(cls:="pure-u-1 pure-u-md-11-24")
@canvas(id:="canvas1", display:="block")
@@ -17,31 +17,30 @@
@sect("Intro to Scala.js")
@Intro.template
- @sect("Hands On")
- @sect("Getting Started")
- @handson.GettingStarted.template
+ @sect("Getting Started")
+ @handson.GettingStarted.template
- @sect("Making a Canvas App")
- @handson.CanvasApp.template
+ @sect("Making a Canvas App")
+ @handson.CanvasApp.template
- @sect("Interactive Web Pages")
- @handson.WebPage.template
+ @sect("Interactive Web Pages")
+ @handson.WebPage.template
- @sect("Cross-platform Modules")
- @handson.CrossModules.template
+ @sect("Cross-platform Modules")
+ @handson.CrossModules.template
- @sect("Client-Server Integration")
- @handson.ClientServer.template
+ @sect("Client-Server Integration")
+ @handson.ClientServer.template
- @sect("Scala.js in Depth")
- @sect("Javascript Interoperability")
- @indepth.JavascriptInterop.template
+@sect("Scala.js in Depth", "Exploring Scala.js")
+ @sect("Javascript Interoperability")
+ @indepth.JavascriptInterop.template
- @sect("Scala.js/Scala-JVM Differences")
- @indepth.SemanticDifferences.template
+ @sect("Deviations from Scala-JVM")
+ @indepth.SemanticDifferences.template
- @sect("The Scala.js Compilation Pipeline")
- @indepth.CompilationPipeline.template
+ @sect("The Compilation Pipeline")
+ @indepth.CompilationPipeline.template
- @sect("Scala.js' Design Space")
- @indepth.DesignSpace.template \ No newline at end of file
+ @sect("Scala.js' Design Space")
+ @indepth.DesignSpace.template \ No newline at end of file
diff --git a/book/src/main/scalatex/book/Intro.scalatex b/book/src/main/scalatex/book/Intro.scalatex
index b7c5268..4e09d99 100644
--- a/book/src/main/scalatex/book/Intro.scalatex
+++ b/book/src/main/scalatex/book/Intro.scalatex
@@ -164,7 +164,7 @@
@p
After going through this chapter and following along with the exercises, you should have a good sense of how Scala.js works and how it feels building things in Scala.js. You would not be an expert, but you'll know where to get started if you decide to try out Scala.js for your next project.
- @sect{Scala.js in Depth}
+ @sect{In Depth}
@p
This section of the book will cover lots of content that does not fit in the earlier Hands-On portion of the book. Things that aren't immediately necessary to get something up and running, things that only advanced users would care about, things that you probably don't need to know but you'd like to know out of intellectual curiosity.
diff --git a/book/src/main/scalatex/book/handson/CanvasApp.scalatex b/book/src/main/scalatex/book/handson/CanvasApp.scalatex
index ba76493..4d0e2ae 100644
--- a/book/src/main/scalatex/book/handson/CanvasApp.scalatex
+++ b/book/src/main/scalatex/book/handson/CanvasApp.scalatex
@@ -21,7 +21,7 @@
@p
To begin with, lets remove all the existing stuff in our @code{.scala} file and leave only the @hl.scala{object} and the @hl.scala{main} method. Let's start off with some necessary boilerplate:
- @hl.ref("examples/src/main/scala/canvasapp/ScratchPad.scala", "/*setup*/", end = "/*code*/")
+ @hl.ref("examples/demos/src/main/scala/canvasapp/ScratchPad.scala", "/*setup*/", end = "/*code*/")
@p
As described earlier, this code uses the @hl.javascript{document.getElementById} function to fish out the @code{canvas} element that we interested in from the DOM. It then gets a rendering context from that @code{canvas}, and sets the height and width of the canvas to completely fill its containing element. Lastly, it fills out the canvas light-gray, so that we can see it on the page.
@@ -31,7 +31,7 @@
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/canvasapp/ScratchPad.scala", "/*code*/")
+ @hl.ref("examples/demos/src/main/scala/canvasapp/ScratchPad.scala", "/*code*/")
@div(cls:="pure-u-1 pure-u-md-11-24")
@canvas(id:="canvas2", display:="block")
@@ -56,7 +56,7 @@
@p
Again, we need roughly the same boilerplate as just now to set up the canvas:
- @hl.ref("examples/src/main/scala/canvasapp/Clock.scala", "/*setup*/", "/*code*/")
+ @hl.ref("examples/demos/src/main/scala/canvasapp/Clock.scala", "/*setup*/", "/*code*/")
@p
The only thing unusual here is that I'm going to create a @hl.scala{linearGradient} in order to make the stopwatch look pretty. This is by no means necessary, and you could simply make the @hl.scala{fillStyle} @hl.scala{"black"} if you want to keep things simple.
@@ -66,7 +66,7 @@
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/canvasapp/Clock.scala", "/*code*/")
+ @hl.ref("examples/demos/src/main/scala/canvasapp/Clock.scala", "/*code*/")
@div(cls:="pure-u-1 pure-u-md-11-24")
@canvas(id:="canvas3", display:="block")
@@ -99,7 +99,7 @@
It's a relatively simple game, but there should be enough "business logic" in here that we won't be simply gluing together APIs. Let's start!
@sect{Setting Up the Canvas}
- @hl.ref("examples/src/main/scala/canvasapp/FlappyLine.scala", "/*setup*/", end="/*variables*/")
+ @hl.ref("examples/demos/src/main/scala/canvasapp/FlappyLine.scala", "/*setup*/", end="/*variables*/")
@p
This section of the code is peripherally necessary, but not core to the implementation or logic of Flappy Box. We see the same @hl.scala{canvas}/@hl.scala{renderer} logic we've seen in all our examples, along with some logic to make the canvas a reasonable size, and some configuration of how we will render text to the canvas.
@@ -108,7 +108,7 @@
In general, code like this will usually end up being necessary in a Scala.js program: the Javascript APIs that the browser provides to do things often ends up being somewhat roundabout and verbose. It's somewhat annoying to have to do for a small program such as this one, but in a larger application, the cost is both spread out over thousands of lines of code and also typically hidden away in some helpers, so you don't have to mess with this stuff unless you really want to.
@sect{Defining our State}
- @hl.ref("examples/src/main/scala/canvasapp/FlappyLine.scala", "/*variables*/", end="def runDead")
+ @hl.ref("examples/demos/src/main/scala/canvasapp/FlappyLine.scala", "/*variables*/", end="def runDead")
@p
This is where we start defining things that are relevant to Flappy Box. There are roughly two groups of values here: immutable constants in the top group, and mutable variables in the bottom. The rough meaning of each variable is documented in the comments, and we'll see exactly how we use them later.
@@ -117,7 +117,7 @@
One notable thing is that we're using a @hl.scala{collection.mutable.Queue} to store the list of obstacles. This is defined in the Scala standard library; in general, all the collections in the Scala standard library can be used without issue in Scala.js.
@sect{Game Logic}
- @hl.ref("examples/src/main/scala/canvasapp/FlappyLine.scala", "def runLive", "def runDead")
+ @hl.ref("examples/demos/src/main/scala/canvasapp/FlappyLine.scala", "def runLive", "def runDead")
@p
The @hl.scala{runLive} function is the meat of Flappy Box. In it, we
@@ -137,13 +137,13 @@
@p
This function basically contains all the game logic, from motion, to collision-detection, to rendering, so it's pretty large. Not that large though! And entirely understandable, even if it takes a few moments to read through.
- @hl.ref("examples/src/main/scala/canvasapp/FlappyLine.scala", "def runDead", end="def run")
+ @hl.ref("examples/demos/src/main/scala/canvasapp/FlappyLine.scala", "def runDead", end="def run")
@p
This is the function that handles what happens when you're dead. Essentially, we reset all the mutable variables to their initial state, and just count down the @hl.scala{dead} counter until it reaches zero and we're considered alive again.
@sect{A Working Product}
- @hl.ref("examples/src/main/scala/canvasapp/FlappyLine.scala", "def run()")
+ @hl.ref("examples/demos/src/main/scala/canvasapp/FlappyLine.scala", "def run()")
@p
And finally, this is the code that kicks everything off: we define the @hl.scala{run} function to swap between @hl.scala{runLive} and @hl.scala{runDead}, register an @hl.scala{canvas.onclick} handler to make the player jump by tweaking his velocity, and we call @code{setInterval} to run the @hl.scala{run} function every 20 milliseconds.
diff --git a/book/src/main/scalatex/book/handson/CrossModules.scalatex b/book/src/main/scalatex/book/handson/CrossModules.scalatex
index 30404ce..9b1f62c 100644
--- a/book/src/main/scalatex/book/handson/CrossModules.scalatex
+++ b/book/src/main/scalatex/book/handson/CrossModules.scalatex
@@ -1 +1,16 @@
-TODO \ No newline at end of file
+@p
+ We've spent several chapters exploring the experience of making web apps using Scala.js, but any large app (web or not!) likely relies on a host of libraries in order to implement large chunks of its functionality. Ideally these libraries would be re-usable, and can be shared among different projects, teams or even companies.
+@p
+ In JVM-land, the standard method for distributing these libraries is as @a("Maven Artifacts", href:="http://stackoverflow.com/questions/2487485/what-is-maven-artifact"). These are typically published in a public location such as @a("Maven Central", href:="http://search.maven.org/"), where others can find and download them for use. Typically downloads are done automatically by the build-tool: in Scala-JVM typically this is SBT.
+@p
+ In Javascript-land, there are multiple ways of acquiring dependencies: @a("CommonJS", href:="http://en.wikipedia.org/wiki/CommonJS") and @a("RequireJS/AMD", href:="http://requirejs.org/") are two competing standards with a host of implementations. Historically, a third approach has been most common: the developer would simply download the modules himself, check it into source-control and manually add a @hl.html{<script>} tag to the HTML page that will make the functionality available through some global variable.
+@p
+ In Scala.js, we side with the JVM standard of distributing libraries as maven jars. This lets us take advantage of all the existing tooling around Scala to handle these jars (SBT, Ivy, Maven Central, etc.) which is far more mature and cohesive than the story in Javascript-land. For example, the Scalatags library we used in the earlier is @a("published on maven central", href:="http://search.maven.org/#search%7Cga%7C1%7Cscalatags"), and adding one line to SBT is enough to pull it down and include it in our project.
+
+@p
+ One interesting wrinkle in Scala.js's case is that since Scala can compile to both Scala.js and Scala-JVM, it is entirely possible to publish a library that can run on both client and server! This chapter will explore the process of building, testing, and publishing such a library.
+
+@sect{A Sample Project}
+
+ @p
+ As always, we will start with an example: in this case a tiny library whose sole purpose in life is to take a series of timestamps (milliseconds UTC) and format them into a list of strings.
diff --git a/book/src/main/scalatex/book/handson/WebPage.scalatex b/book/src/main/scalatex/book/handson/WebPage.scalatex
index 1e8cf3f..c3f66a4 100644
--- a/book/src/main/scalatex/book/handson/WebPage.scalatex
+++ b/book/src/main/scalatex/book/handson/WebPage.scalatex
@@ -13,7 +13,7 @@
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/webpage/HelloWorld0.scala")
+ @hl.ref("examples/demos/src/main/scala/webpage/HelloWorld0.scala")
@div(cls:="pure-u-1 pure-u-md-11-24")
@div(id:="div1")
@@ -36,14 +36,14 @@
@p
@a("Scalatags", href:="https://github.com/lihaoyi/scalatags") is a cross-platform Scala.js/Scala-JVM library that is designed to generate HTML. To use Scalatags, you need to add it as a dependency to your Scala.js SBT project, in the @code{build.sbt} file:
- @hl.ref("examples/build.sbt", "com.scalatags")
+ @hl.ref("examples/demos/build.sbt", "com.scalatags")
@p
With that, the above snippet of code re-written using Scalatags looks as follows:
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/webpage/HelloWorld1.scala")
+ @hl.ref("examples/demos/src/main/scala/webpage/HelloWorld1.scala")
@div(cls:="pure-u-1 pure-u-md-11-24")
@div(id:="div2")
@@ -58,7 +58,7 @@
@sect{User Input}
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/webpage/Inputs.scala", "val box")
+ @hl.ref("examples/demos/src/main/scala/webpage/Inputs.scala", "val box")
@div(cls:="pure-u-1 pure-u-md-11-24")
@div(id:="div3")
@@ -77,12 +77,12 @@
@p
To begin with, let's define our list of items: Fruits!
- @hl.ref("examples/src/main/scala/webpage/Search0.scala", "val listings", "def")
+ @hl.ref("examples/demos/src/main/scala/webpage/Search0.scala", "val listings", "def")
@p
Next, let's think about how we want to render these fruits. One natural way would be as a list, which in HTML is represented by a @hl.html{<ul>} with @hl.html{<li>}s inside of it if we wanted the list to be unordered. We'll make it a @hl.scala{def}, because we know up-front we're going to need to re-render this listing as the search query changes. Lastly, we know we want 1 list item for each fruit, but only if the fruit starts with the search query.
- @hl.ref("examples/src/main/scala/webpage/Search0.scala", "def renderListings", "lazy val")
+ @hl.ref("examples/demos/src/main/scala/webpage/Search0.scala", "def renderListings", "lazy val")
@p
Using a @hl.scala{for}-loop with a filter inside the Scalatags fragment is just normal Scala, since you can nest arbitrary Scala expressions inside a Scalatags snippet. In this case, we're converting both the fruit and the search query to lower case so we can compare them case-insensitively.
@@ -92,7 +92,7 @@
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/webpage/Search0.scala", "val output")
+ @hl.ref("examples/demos/src/main/scala/webpage/Search0.scala", "val output")
@div(cls:="pure-u-1 pure-u-md-11-24")
@div(id:="div4")
@@ -103,7 +103,7 @@
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/webpage/Search1.scala", "def renderListings", "lazy val")
+ @hl.ref("examples/demos/src/main/scala/webpage/Search1.scala", "def renderListings", "lazy val")
@div(cls:="pure-u-1 pure-u-md-11-24")
@div(id:="div5")
@@ -136,7 +136,7 @@
@sect{Raw Javascript}
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/webpage/Weather0.scala", "val xhr")
+ @hl.ref("examples/demos/src/main/scala/webpage/Weather0.scala", "val xhr")
@div(cls:="pure-u-1 pure-u-md-11-24")
@div(id:="div6")
@@ -149,7 +149,7 @@
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/resources/webpage/weather.js", "var xhr")
+ @hl.ref("examples/demos/src/main/resources/webpage/weather.js", "var xhr")
@div(cls:="pure-u-1 pure-u-md-11-24")
@div(id:="div7")
@@ -177,7 +177,7 @@
@p
With Scala.js, we provide a simpler API that is more clearly functional. First, you need to import some things into scope:
- @hl.ref("examples/src/main/scala/webpage/Weather1.scala", "import dom", "val url =")
+ @hl.ref("examples/demos/src/main/scala/webpage/Weather1.scala", "import dom", "val url =")
@p
The first import brings in Scala adapters to several DOM APIs, which allow you to use them more idiomatically from Scala. The second brings in an implicit @hl.scala{ExecutionContext} that we'll need to run our asynchronous operations.
@@ -187,7 +187,7 @@
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/webpage/Weather1.scala", "val url")
+ @hl.ref("examples/demos/src/main/scala/webpage/Weather1.scala", "val url")
@div(cls:="pure-u-1 pure-u-md-11-24")
@div(id:="div8")
@@ -205,7 +205,7 @@
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/webpage/Weather2.scala", "Ajax.get")
+ @hl.ref("examples/demos/src/main/scala/webpage/Weather2.scala", "Ajax.get")
@div(cls:="pure-u-1 pure-u-md-11-24")
@div(id:="div9")
@@ -219,7 +219,7 @@
@div(cls:="pure-g")
@div(cls:="pure-u-1 pure-u-md-13-24")
- @hl.ref("examples/src/main/scala/webpage/Weather3.scala", "Ajax.get")
+ @hl.ref("examples/demos/src/main/scala/webpage/Weather3.scala", "Ajax.get")
@div(cls:="pure-u-1 pure-u-md-11-24")
@div(id:="div10")
@@ -235,12 +235,12 @@
@p
At this point we've made a small app that allows us to search from a pre-populated list of words, as well as a small app that lets us query a remote web-service to find the weather in Singapore. The natural thing to do is to put these things together to make a app that will let us search from a list of countries and query the weather in any country we desire. Let's start!
- @hl.ref("examples/src/main/scala/webpage/WeatherSearch.scala", "lazy val box", "def fetchWeather")
+ @hl.ref("examples/demos/src/main/scala/webpage/WeatherSearch.scala", "lazy val box", "def fetchWeather")
@p
This sets up the basics: an input box, an output div, and sets an @hl.scala{onkeyup} that fetches the weather data each time you hit a key. It then renders all these components and sticks them into the @hl.scala{target} div. This is basically the same stuff we saw in the early examples, with minor tweaks e.g. adding a @hl.scala{maxHeight} and @hl.scala{overflowY:="scroll"} to the @hl.scala{output} box in case the output is too large. Whenever we enter something in the box, we call the function @hl.scala{fetchWeather}, which is defined as:
- @hl.ref("examples/src/main/scala/webpage/WeatherSearch.scala", "def fetchWeather", "def showResults")
+ @hl.ref("examples/demos/src/main/scala/webpage/WeatherSearch.scala", "def fetchWeather", "def showResults")
@p
This is where the actual data fetching happens. It's relatively straightforward: we make an @hl.scala{Ajax.get} request, @hl.scala{JSON.parse} the response, and feed it into the callback function. We're using a slightly different API from earlier: we now have the @hl.scala{"type=like"} flag, which is documented in the @a("OpenWeatherMap API docs", href:="http://openweathermap.org/current#other") to return multiple results for each city whose name matches your query.
@@ -248,7 +248,7 @@
@p
Notably, before we re-render the results, we check whether the @hl.scala{query} that was passed in is the same value that's in the @hl.scala{box}. This is to prevent a particularly slow ajax call from finishing out-of-order, potentially stomping over the results of more recent searches. We also check whether the @hl.scala{.list: js.Dynamic} property we want is an instance of @hl.scala{js.Array}: if it isn't, it means we don't have any results to show, and we can skip the whole render-output step.
- @hl.ref("examples/src/main/scala/webpage/WeatherSearch.scala", "def showResults")
+ @hl.ref("examples/demos/src/main/scala/webpage/WeatherSearch.scala", "def showResults")
@p
Here is the meat and potatoes of this program: every time it gets called with an array of weather-data, we iterate over the cities in that array. It then does a similar sort of data-extraction that we did earlier, putting the results into the @hl.scala{output} div we defined above, including highlighting.
diff --git a/build.sbt b/build.sbt
index d7994be..5aacd9a 100644
--- a/build.sbt
+++ b/build.sbt
@@ -37,11 +37,11 @@ lazy val book = Project(
"org.eclipse.jgit" % "org.eclipse.jgit" % "3.5.1.201410131835-r"
),
(resources in Compile) += {
- (fastOptJS in (examples, Compile)).value
- (artifactPath in (examples, Compile, fastOptJS)).value
+ (fastOptJS in (demos, Compile)).value
+ (artifactPath in (demos, Compile, fastOptJS)).value
},
(unmanagedResourceDirectories in Compile) ++=
- (unmanagedResourceDirectories in (examples, Compile)).value,
+ (unmanagedResourceDirectories in (demos, Compile)).value,
scalacOptions in Compile ++= {
val jar = (Keys.`package` in (scalatexPlugin, Compile)).value
val addPlugin = "-Xplugin:" + jar.getAbsolutePath
@@ -59,4 +59,4 @@ lazy val book = Project(
}
)
-lazy val examples = project.in(file("examples")) \ No newline at end of file
+lazy val demos = project.in(file("examples/demos")) \ No newline at end of file
diff --git a/examples/crossBuilds/simple/build.sbt b/examples/crossBuilds/simple/build.sbt
new file mode 100644
index 0000000..df0c84b
--- /dev/null
+++ b/examples/crossBuilds/simple/build.sbt
@@ -0,0 +1,8 @@
+lazy val js = project.in(file("js")).settings(scalaJSSettings:_*).settings(
+ unmanagedSourceDirectories in Compile +=
+ baseDirectory.value / ".." / "shared" / "main" / "scala"
+)
+lazy val jvm = project.in(file("jvm")).settings(
+ unmanagedSourceDirectories in Compile +=
+ baseDirectory.value / ".." / "shared" / "main" / "scala"
+) \ No newline at end of file
diff --git a/examples/crossBuilds/simple/js/src/main/scala/simple/Platform.scala b/examples/crossBuilds/simple/js/src/main/scala/simple/Platform.scala
new file mode 100644
index 0000000..40f65f4
--- /dev/null
+++ b/examples/crossBuilds/simple/js/src/main/scala/simple/Platform.scala
@@ -0,0 +1,18 @@
+/*js/src/main/scala/simple/Platform.scala*/
+package simple
+import scala.scalajs.js
+
+object Platform extends js.JSApp{
+ def format(ts: Long) = {
+ new js.Date(ts).toLocaleString();
+ }
+ def main() = {
+ println("simple.js")
+ val times = Seq(
+ System.currentTimeMillis(),
+ System.currentTimeMillis() + 1000,
+ System.currentTimeMillis() + 2000
+ )
+ println(Simple.formatTimestamps(times))
+ }
+} \ No newline at end of file
diff --git a/examples/crossBuilds/simple/jvm/src/main/scala/simple/Platform.scala b/examples/crossBuilds/simple/jvm/src/main/scala/simple/Platform.scala
new file mode 100644
index 0000000..af70429
--- /dev/null
+++ b/examples/crossBuilds/simple/jvm/src/main/scala/simple/Platform.scala
@@ -0,0 +1,23 @@
+/*jvm/src/main/scala/simple/Platform.scala*/
+package simple
+import java.text.SimpleDateFormat
+
+object Platform{
+ def format(ts: Long) = {
+ // http://docs.oracle.com/javase/7/
+ // docs/api/java/text/SimpleDateFormat.html
+ val fmt = "MMMM d, yyyy h:mm:ss aaa z"
+ new SimpleDateFormat(fmt).format(
+ new java.util.Date(ts)
+ )
+ }
+ def main(args: Array[String]) = {
+ println("simple.jvm")
+ val times = Seq(
+ System.currentTimeMillis(),
+ System.currentTimeMillis() + 1000,
+ System.currentTimeMillis() + 2000
+ )
+ println(Simple.formatTimestamps(times))
+ }
+} \ No newline at end of file
diff --git a/examples/crossBuilds/simple/project/build.sbt b/examples/crossBuilds/simple/project/build.sbt
new file mode 100644
index 0000000..5ac559a
--- /dev/null
+++ b/examples/crossBuilds/simple/project/build.sbt
@@ -0,0 +1 @@
+addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % "0.5.5") \ No newline at end of file
diff --git a/examples/crossBuilds/simple/shared/main/scala/simple/Simple.scala b/examples/crossBuilds/simple/shared/main/scala/simple/Simple.scala
new file mode 100644
index 0000000..4e693e4
--- /dev/null
+++ b/examples/crossBuilds/simple/shared/main/scala/simple/Simple.scala
@@ -0,0 +1,9 @@
+/*shared/main/scala/simple/Simple.scala*/
+package simple
+object Simple{
+ def formatTimestamps(timestamps: Seq[Long]) = {
+ timestamps.map(Platform.format)
+ .mkString("\n")
+ }
+ }
+} \ No newline at end of file
diff --git a/examples/build.sbt b/examples/demos/build.sbt
index 7e6b685..7e6b685 100644
--- a/examples/build.sbt
+++ b/examples/demos/build.sbt
diff --git a/examples/src/main/resources/webpage/weather.js b/examples/demos/src/main/resources/webpage/weather.js
index 8e95305..8e95305 100644
--- a/examples/src/main/resources/webpage/weather.js
+++ b/examples/demos/src/main/resources/webpage/weather.js
diff --git a/examples/src/main/scala/Splash.scala b/examples/demos/src/main/scala/Splash.scala
index c68bdca..c68bdca 100644
--- a/examples/src/main/scala/Splash.scala
+++ b/examples/demos/src/main/scala/Splash.scala
diff --git a/examples/src/main/scala/canvasapp/Clock.scala b/examples/demos/src/main/scala/canvasapp/Clock.scala
index af9d8aa..af9d8aa 100644
--- a/examples/src/main/scala/canvasapp/Clock.scala
+++ b/examples/demos/src/main/scala/canvasapp/Clock.scala
diff --git a/examples/src/main/scala/canvasapp/FlappyLine.scala b/examples/demos/src/main/scala/canvasapp/FlappyLine.scala
index 50c9906..50c9906 100644
--- a/examples/src/main/scala/canvasapp/FlappyLine.scala
+++ b/examples/demos/src/main/scala/canvasapp/FlappyLine.scala
diff --git a/examples/src/main/scala/canvasapp/ScratchPad.scala b/examples/demos/src/main/scala/canvasapp/ScratchPad.scala
index cc3d7e0..cc3d7e0 100644
--- a/examples/src/main/scala/canvasapp/ScratchPad.scala
+++ b/examples/demos/src/main/scala/canvasapp/ScratchPad.scala
diff --git a/examples/src/main/scala/webpage/HelloWorld0.scala b/examples/demos/src/main/scala/webpage/HelloWorld0.scala
index df458ac..df458ac 100644
--- a/examples/src/main/scala/webpage/HelloWorld0.scala
+++ b/examples/demos/src/main/scala/webpage/HelloWorld0.scala
diff --git a/examples/src/main/scala/webpage/HelloWorld1.scala b/examples/demos/src/main/scala/webpage/HelloWorld1.scala
index 1dc77b3..1dc77b3 100644
--- a/examples/src/main/scala/webpage/HelloWorld1.scala
+++ b/examples/demos/src/main/scala/webpage/HelloWorld1.scala
diff --git a/examples/src/main/scala/webpage/Inputs.scala b/examples/demos/src/main/scala/webpage/Inputs.scala
index 9339e84..9339e84 100644
--- a/examples/src/main/scala/webpage/Inputs.scala
+++ b/examples/demos/src/main/scala/webpage/Inputs.scala
diff --git a/examples/src/main/scala/webpage/Search0.scala b/examples/demos/src/main/scala/webpage/Search0.scala
index 300b506..300b506 100644
--- a/examples/src/main/scala/webpage/Search0.scala
+++ b/examples/demos/src/main/scala/webpage/Search0.scala
diff --git a/examples/src/main/scala/webpage/Search1.scala b/examples/demos/src/main/scala/webpage/Search1.scala
index 1936898..1936898 100644
--- a/examples/src/main/scala/webpage/Search1.scala
+++ b/examples/demos/src/main/scala/webpage/Search1.scala
diff --git a/examples/src/main/scala/webpage/Weather0.scala b/examples/demos/src/main/scala/webpage/Weather0.scala
index 4a2c6f0..4a2c6f0 100644
--- a/examples/src/main/scala/webpage/Weather0.scala
+++ b/examples/demos/src/main/scala/webpage/Weather0.scala
diff --git a/examples/src/main/scala/webpage/Weather1.scala b/examples/demos/src/main/scala/webpage/Weather1.scala
index c509cb5..c509cb5 100644
--- a/examples/src/main/scala/webpage/Weather1.scala
+++ b/examples/demos/src/main/scala/webpage/Weather1.scala
diff --git a/examples/src/main/scala/webpage/Weather2.scala b/examples/demos/src/main/scala/webpage/Weather2.scala
index aa04059..aa04059 100644
--- a/examples/src/main/scala/webpage/Weather2.scala
+++ b/examples/demos/src/main/scala/webpage/Weather2.scala
diff --git a/examples/src/main/scala/webpage/Weather3.scala b/examples/demos/src/main/scala/webpage/Weather3.scala
index 4dadf94..4dadf94 100644
--- a/examples/src/main/scala/webpage/Weather3.scala
+++ b/examples/demos/src/main/scala/webpage/Weather3.scala
diff --git a/examples/src/main/scala/webpage/WeatherSearch.scala b/examples/demos/src/main/scala/webpage/WeatherSearch.scala
index 0c8acc9..0c8acc9 100644
--- a/examples/src/main/scala/webpage/WeatherSearch.scala
+++ b/examples/demos/src/main/scala/webpage/WeatherSearch.scala
diff --git a/project/build.sbt b/project/build.sbt
index 86ce45d..5ac559a 100644
--- a/project/build.sbt
+++ b/project/build.sbt
@@ -1,2 +1 @@
-
addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % "0.5.5") \ No newline at end of file