diff options
Diffstat (limited to 'book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex')
-rw-r--r-- | book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex | 17 |
1 files changed, 7 insertions, 10 deletions
diff --git a/book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex b/book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex index 171b2d3..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 @@ -177,13 +177,10 @@ @p Overall, these helper functions do nothing special, btu we're defining them first to avoid having to copy-&-paste code throughout the subsequent examples. Now that we've defined all the relevant scaffolding, let's walk through a few ways that we can implement the all-important @hl.scala{handle} method. - @def scrollDiv = div( - height:="200px", - overflow:="scroll" - ) + @def exampleDiv = div(height:="200px") @sect{Direct Use of XMLHttpRequest} - @example(scrollDiv, "Futures().main0") + @example(exampleDiv, "Futures().main0") @hl.ref("examples/demos/src/main/scala/advanced/Futures.scala", "def handle0", "main") @p @@ -195,7 +192,7 @@ This solution is basically equivalent to the initial code given in the @sect.ref{Raw Javascript} section of @sect.ref{Interactive Web Pages}, with the additional code necessary for aggregation. As described in @sect.ref{dom.extensions}, we can make use of the @hl.scala{Ajax} object to make it slightly tidier. @sect{Using dom.extensions.Ajax} - @example(scrollDiv, "Futures().main1") + @example(exampleDiv, "Futures().main1") @hl.ref("examples/demos/src/main/scala/advanced/Futures.scala", "def handle1", "main") @p @@ -204,7 +201,7 @@ However, we still have the messiness inherent in the result aggregation: we don't actually want to perform our action (writing to the @hl.scala{output} div) when one @hl.scala{Future} is complete, but only when @i{all} the @hl.scala{Future}s are complete. Thus we still need to do some amount of manual book-keeping in the @hl.scala{results} buffer. @sect{Future Combinators} - @example(scrollDiv, "Futures().main2") + @example(exampleDiv, "Futures().main2") @hl.ref("examples/demos/src/main/scala/advanced/Futures.scala", "def handle2", "main") @p @@ -287,14 +284,14 @@ @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. @p You may be wondering what these @hl.scala{Channel} things are, and where they are coming from. Although these are not provided by Scala, they are pretty straightforward to define ourselves: - @hl.ref("examples/demos/src/main/scala/advanced/Async.scala", "case class Channel") + @hl.ref("examples/demos/src/main/scala/advanced/Async.scala", "class Channel") @p The point of @hl.scala{Channel} is to allow us to turn event-callbacks (like those provided by the DOM's @hl.scala{onmouseXXX} properties) into some kind of event-stream, that we can listen to asynchronously (via @hl.scala{apply} that returns a @hl.scala{Future}) or merge via @hl.scala{|}. This is a minimal implementation for what we need now, but it would be easy to provide more functionality (filter, map, etc.) as necessary. |