From 7ca2e125c17bd541340bce55623bd40cf88ce64f Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 20 Nov 2014 02:07:02 -0800 Subject: Scala-async chapter works --- examples/demos/build.sbt | 6 +- examples/demos/src/main/scala/advanced/Async.scala | 120 +++++++++++++++++++++ .../demos/src/main/scala/advanced/BasicRx.scala | 80 ++++++++++++++ .../demos/src/main/scala/advanced/Futures.scala | 13 +++ .../src/main/scala/scrollmenu/Controller.scala | 3 + 5 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 examples/demos/src/main/scala/advanced/Async.scala create mode 100644 examples/demos/src/main/scala/advanced/BasicRx.scala create mode 100644 examples/demos/src/main/scala/advanced/Futures.scala (limited to 'examples/demos') diff --git a/examples/demos/build.sbt b/examples/demos/build.sbt index fb79984..5b55829 100644 --- a/examples/demos/build.sbt +++ b/examples/demos/build.sbt @@ -14,4 +14,8 @@ libraryDependencies += "com.lihaoyi" %%% "upickle" % "0.2.5" libraryDependencies += "org.scala-lang.modules.scalajs" %%% "scalajs-dom" % "0.6" -libraryDependencies += "com.scalatags" %%% "scalatags" % "0.4.2" \ No newline at end of file +libraryDependencies += "com.scalatags" %%% "scalatags" % "0.4.2" + +libraryDependencies += "com.scalarx" %%% "scalarx" % "0.2.6" + +libraryDependencies += "org.scala-lang.modules" %% "scala-async" % "0.9.2" \ No newline at end of file diff --git a/examples/demos/src/main/scala/advanced/Async.scala b/examples/demos/src/main/scala/advanced/Async.scala new file mode 100644 index 0000000..481e80e --- /dev/null +++ b/examples/demos/src/main/scala/advanced/Async.scala @@ -0,0 +1,120 @@ +package advanced + +import org.scalajs.dom +import concurrent._ +import async.Async._ +import scala.scalajs.js.annotation.JSExport +import scalajs.concurrent.JSExecutionContext.Implicits.queue + +@JSExport +object Async { + def init(canvas: dom.HTMLCanvasElement) = { + val renderer = canvas.getContext("2d") + .asInstanceOf[dom.CanvasRenderingContext2D] + + canvas.style.backgroundColor = "#f8f8f8" + canvas.height = canvas.parentElement.clientHeight + canvas.width = canvas.parentElement.clientWidth + + renderer.lineWidth = 5 + renderer.strokeStyle = "red" + renderer.fillStyle = "cyan" + renderer + } + @JSExport + def main(canvas: dom.HTMLCanvasElement) = { + val renderer = init(canvas) + // async + def rect = canvas.getBoundingClientRect() + + type ME = dom.MouseEvent + val mousemove = + Channel[ME](canvas.onmousemove = _) + val mouseup = + Channel[ME](canvas.onmouseup = _) + val mousedown = + Channel[ME](canvas.onmousedown = _) + + async{ + while(true){ + val start = await(mousedown()) + renderer.beginPath() + renderer.moveTo( + start.clientX - rect.left, + start.clientY - rect.top + ) + + var res = await(mousemove | mouseup) + while(res.`type` == "mousemove"){ + renderer.lineTo( + res.clientX - rect.left, + res.clientY - rect.top + ) + renderer.stroke() + res = await(mousemove | mouseup) + } + + renderer.fill() + await(mouseup()) + renderer.clearRect(0, 0, 1000, 1000) + } + } + } + @JSExport + def main0(canvas: dom.HTMLCanvasElement) = { + val renderer = init(canvas) + // traditional + def rect = canvas.getBoundingClientRect() + + var dragState = 0 + + canvas.onmousemove ={(e: dom.MouseEvent) => + if (dragState == 1) { + renderer.lineTo( + e.clientX - rect.left, + e.clientY - rect.top + ) + renderer.stroke() + } + } + canvas.onmouseup = {(e: dom.MouseEvent) => + if(dragState == 1) { + renderer.fill() + dragState = 2 + }else if (dragState == 2){ + renderer.clearRect(0, 0, 1000, 1000) + dragState = 0 + } + } + canvas.onmousedown ={(e: dom.MouseEvent) => + if (dragState == 0) { + dragState = 1 + renderer.beginPath() + renderer.moveTo( + e.clientX - rect.left, + e.clientY - rect.top + ) + } + } + } +} + +case class Channel[T](init: (T => Unit) => Unit){ + init(update) + private[this] var value: Promise[T] = null + def apply(): Future[T] = { + value = Promise[T]() + value.future + } + def update(t: T): Unit = { + if (value != null && !value.isCompleted) value.success(t) + } + def |(other: Channel[T]): Future[T] = { + val p = Promise[T]() + for{ + f <- Seq(other(), this()) + t <- f + } p.trySuccess(t) + p.future + } +} \ No newline at end of file diff --git a/examples/demos/src/main/scala/advanced/BasicRx.scala b/examples/demos/src/main/scala/advanced/BasicRx.scala new file mode 100644 index 0000000..56b41b0 --- /dev/null +++ b/examples/demos/src/main/scala/advanced/BasicRx.scala @@ -0,0 +1,80 @@ +package advanced + +import org.scalajs.dom +import scala.scalajs.js +import scala.scalajs.js.annotation.JSExport +import rx._ +import scalatags.JsDom.all._ + +@JSExport +object BasicRx { + @JSExport + def main(container: dom.HTMLDivElement) = { + val txt = Var("") + val numChars = Rx{txt().length} + val numWords = Rx{ + txt().split(' ') + .filter(_.length > 0) + .length + } + + val avgWordLength = Rx{ + txt().count(_ != ' ') * 1.0 / numWords() + } + + val txtInput = textarea.render + txtInput.onkeyup = (e: dom.Event) => { + txt() = txtInput.value + } + + container.appendChild( + div( + txtInput, + ul( + li("Chars: ", numChars), + li("Words: ", numWords), + li("Word Length: ", avgWordLength) + ) + ).render + ) + } + @JSExport + def main2(container: dom.HTMLDivElement) = { + val fruits = Seq( + "Apple", "Apricot", "Banana", "Cherry", + "Mango", "Mangosteen", "Mandarin", + "Grape", "Grapefruit", "Guava" + ) + val query = Var("") + val txtInput = input.render + txtInput.onkeyup = (e: dom.Event) => { + query() = txtInput.value + } + + val fragments = + for(fruit <- fruits) yield Rx { + val shown = fruit.toLowerCase + .startsWith(query()) + if (shown) li(fruit) + else li(display := "none") + } + + container.appendChild( + div( + txtInput, + ul(fragments) + ).render + ) + } + implicit def rxFrag[T <% Frag](r: Rx[T]): Frag = { + def rSafe: dom.Node = span(r()).render + var last = rSafe + Obs(r, skipInitial = true){ + val newLast = rSafe + js.Dynamic.global.last = last + last.parentNode.replaceChild(newLast, last) + last = newLast + } + last + } +} diff --git a/examples/demos/src/main/scala/advanced/Futures.scala b/examples/demos/src/main/scala/advanced/Futures.scala new file mode 100644 index 0000000..4035fac --- /dev/null +++ b/examples/demos/src/main/scala/advanced/Futures.scala @@ -0,0 +1,13 @@ +package advanced + +import org.scalajs.dom + +import scala.scalajs.js.annotation.JSExport + +@JSExport +object Futures { + @JSExport + def main(container: dom.HTMLDivElement) = { + + } +} diff --git a/examples/demos/src/main/scala/scrollmenu/Controller.scala b/examples/demos/src/main/scala/scrollmenu/Controller.scala index 132a073..119b8d4 100644 --- a/examples/demos/src/main/scala/scrollmenu/Controller.scala +++ b/examples/demos/src/main/scala/scrollmenu/Controller.scala @@ -70,6 +70,9 @@ object Controller{ menu.appendChild( div(cls:="pure-menu pure-menu-open")( + a(cls:="pure-menu-heading")( + "Contents" + ), list ).render ) -- cgit v1.2.3