summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorLi Haoyi <haoyi@dropbox.com>2014-11-13 00:56:59 -0800
committerLi Haoyi <haoyi@dropbox.com>2014-11-13 00:56:59 -0800
commit3beb1dd285d89dd4b746b1c4cd287a8748376556 (patch)
tree071d5c4fd22c83fa6889a891161b0387e1f49e06 /examples
parent7f33cb682200a501e0a48ab2fbad688317d80754 (diff)
downloadhands-on-scala-js-3beb1dd285d89dd4b746b1c4cd287a8748376556.tar.gz
hands-on-scala-js-3beb1dd285d89dd4b746b1c4cd287a8748376556.tar.bz2
hands-on-scala-js-3beb1dd285d89dd4b746b1c4cd287a8748376556.zip
Commit after converting to React.js
Diffstat (limited to 'examples')
-rw-r--r--examples/demos/Controller.scala214
-rw-r--r--examples/demos/build.sbt2
2 files changed, 83 insertions, 133 deletions
diff --git a/examples/demos/Controller.scala b/examples/demos/Controller.scala
index 0936776..e17cde9 100644
--- a/examples/demos/Controller.scala
+++ b/examples/demos/Controller.scala
@@ -1,4 +1,7 @@
+import japgolly.scalajs.react.React
+import japgolly.scalajs.react.vdom.VDomBuilder
+
import scala.scalajs.js
import scala.scalajs.js.annotation.JSExport
import org.scalajs.dom
@@ -6,15 +9,7 @@ import org.scalajs.dom.extensions._
import scala.collection.mutable
import scalatags.JsDom.all._
-object Renderer{
- import japgolly.scalajs.react._ // React
- import vdom.ReactVDom._ // Scalatags → React virtual DOM
- import vdom.ReactVDom.all._ // Scalatags html & css (div, h1, textarea, etc.)
-
- val Menu = ReactComponentB[Int]("Menu").render{ p =>
- }.build
-}
case class Tree[T](name: T, children: Vector[Tree[T]])
@JSExport
object Controller{
@@ -38,6 +33,14 @@ object Controller{
def main(data: scala.scalajs.js.Any) = {
val structure = upickle.readJs[Tree[String]](upickle.json.readJs(data))
+ var i = 0
+ def recurse(t: Tree[String]): Tree[(String, String, Int)] = {
+ val curr = (t.name, munge(t.name), i)
+ i += 1
+ val children = t.children.map(recurse)
+ Tree(curr, children)
+ }
+
val Seq(main, menu, layout, menuLink) = Seq(
"main", "menu", "layout", "menuLink"
@@ -47,43 +50,6 @@ object Controller{
snippets.foreach(js.Dynamic.global.hljs.highlightBlock(_))
- val contentTree = {
- def rec(current: Tree[String], depth: Int): Tree[dom.HTMLElement] = {
- val myCls =
- "menu-item" +
- (if (depth <= 1) " menu-item-divided" else "")
-
- val frag =
- li(
- paddingLeft := s"${depth * 15}px",
- a(
- current.name,
- href:="#"+munge(current.name),
- cls:=myCls
- )
- ).render
- Tree(frag, current.children.map(rec(_, depth + 1)))
- }
- rec(structure, 0)
- }
- val contentList = {
- def rec(current: Tree[dom.HTMLElement]): Seq[dom.HTMLElement] = {
- current.name +: current.children.flatMap(rec)
- }
- rec(contentTree).toVector
- }
-
- val frag = div(cls:="pure-menu pure-menu-open")(
- a(cls:="pure-menu-heading", href:="#")(
- "Contents"
- ),
- ul(cls:="menu-item-list")(
- contentList.drop(1)
- )
- )
- menu.appendChild(frag.render)
-
-
val headers = {
def offset(el: dom.HTMLElement, parent: dom.HTMLElement): Double = {
if (el == parent) 0
@@ -101,50 +67,33 @@ object Controller{
.toVector
}
- scrollSpy(main, headers, contentList, contentTree)
+ val menuBar = React.renderComponent(
+ Menu(recurse(structure)),
+ menu
+ )
menuLink.onclick = (e: dom.MouseEvent) => {
toggleClass(layout, "active")
toggleClass(menu, "active")
toggleClass(menuLink, "active")
}
- }
-
- /**
- * Needs to be done in a sketchy imperative fashion for performance:
- * onscroll gets called quite a lot, so any additional work makes it
- * noticeable jerky
- */
- def scrollSpy(main: dom.HTMLElement,
- headers: Vector[Double],
- contentList: Vector[dom.HTMLElement],
- contentTree: Tree[dom.HTMLElement]) = {
-
-
var scrolling = false
- var lastIndex = -1
- def run() = {
- scrolling = false
- val threshold = main.scrollTop + main.clientHeight
-
- var index = 0
- while(index < headers.length && index >= 0){
- index += 1
- if (headers(index) > threshold) index *= -1
- }
- index = -index
-
- if (index != lastIndex){
- updateSideBar(lastIndex, index, contentList, contentTree)
- lastIndex = index
- }
- }
- run()
main.onscroll = (e: dom.UIEvent) => {
if (!scrolling){
scrolling = true
- dom.requestAnimationFrame((d: Double) => run())
+ dom.requestAnimationFrame{(d: Double) =>
+ scrolling = false
+ val threshold = main.scrollTop + main.clientHeight
+
+ var index = 0
+ while(index < headers.length && index >= 0){
+ index += 1
+ if (headers(index) > threshold) index *= -1
+ }
+ index = -index
+ menuBar.setState(index)
+ }
}
}
}
@@ -152,64 +101,65 @@ object Controller{
val rect = el.getBoundingClientRect()
rect.top >= 0 && rect.bottom <= dom.innerHeight
}
- val lastShown = new js.Array[dom.HTMLElement](0)
- val lastLined = new js.Array[dom.HTMLElement](0)
- def updateSideBar(lastIndex: Int,
- index: Int,
- contentList: Vector[dom.HTMLElement],
- contentTree: Tree[dom.HTMLElement]) = {
-
- println(s"MOVING $lastIndex -> $index")
- if (!isElementInViewport(contentList(index))) {
- contentList(index).scrollIntoView(lastIndex > index)
- }
- val shown = new js.Array[dom.HTMLElement](0)
- val lined = new js.Array[dom.HTMLElement](0)
- /**
- * Makes two passes over the children list; once to determine if
- * the current element is a parent of the current header, and another
- * to mark all the children of the current element with the correct
- * CSS classes.
- */
- def rec(curr: Tree[dom.HTMLElement]): Boolean = {
-
- var found = false
+
+ import japgolly.scalajs.react._ // React
+ import vdom.ReactVDom._ // Scalatags → React virtual DOM
+ import vdom.ReactVDom.all._ // Scalatags html & css (div, h1, textarea, etc.)
+
+ val Menu = ReactComponentB[Tree[(String, String, Int)]]("Menu")
+ .getInitialState(_ => 0)
+ .render{ (structure, _, index) =>
+
+ val contentList = {
var i = 0
- var j = 0
- while (j < curr.children.length){
- val x = curr.children(j)
- j+= 1
- val f = rec(x)
- found |= f
- if (!found) i += 1
+ def rec1(current: Tree[(String, String, Int)]): Tree[(String, String, Int, Boolean)] = {
+ val initialI = i
+ i += 1
+ val children = current.children.map(rec1)
+
+ val win = i >= index && initialI < index
+ Tree(
+ (current.name._1, current.name._2, current.name._3, win),
+ children
+ )
}
+ def rec(current: Tree[(String, String, Int, Boolean)],
+ depth: Int,
+ classes: String): Iterator[Tag] = {
- if (found || curr.name == contentList(index)){
- var j = 0
- while (j < curr.children.length){
- val x = curr.children(j)
- if (found && i > 0){
- lined.push(x.name)
- i -= 1
- }
+ val winIndex = current.children.indexWhere(_.name._4)
+ val (before, after) = current.children.splitAt(winIndex)
- j+= 1
- shown.push(x.name)
- }
- lined.push(curr.name)
- true
- }else false
+ val myCls =
+ "menu-item" +
+ (if (depth <= 1) " menu-item-divided" else "")
+ val (name, munged, currIndex, win) = current.name
+ val frag =
+ li(paddingLeft := s"${depth * 15}px")(
+ a(
+ name,
+ href:="#"+munged,
+ cls:=myCls
+ ),
+ cls:=classes + (if (win) " pure-menu-selected" else "")
+ )
+ val afterCls = if (!win) "hide" else ""
+ Iterator(frag) ++
+ before.flatMap(rec(_, depth+1, "lined")) ++
+ after.flatMap(rec(_, depth+1, afterCls))
+ }
+ rec(rec1(structure), 0, "")
}
- rec(contentTree)
- for(el <- contentList){
- if (shown.indexOf(el) != -1) removeClass(el, "hide")
- else addClass(el, "hide")
- if (lined.indexOf(el) == -1) removeClass(el, "lined")
- else addClass(el, "lined")
- }
- if (lastIndex != -1) removeClass(contentList(lastIndex), "pure-menu-selected")
- addClass(contentList(index), "pure-menu-selected")
- }
-}
+ val frag = div(cls:="pure-menu pure-menu-open")(
+ a(cls:="pure-menu-heading", href:="#")(
+ "Contents"
+ ),
+ ul(cls:="menu-item-list")(
+ contentList.drop(1).toVector
+ )
+ )
+ frag
+ }.build
+} \ No newline at end of file
diff --git a/examples/demos/build.sbt b/examples/demos/build.sbt
index 9be4d4d..040f9fd 100644
--- a/examples/demos/build.sbt
+++ b/examples/demos/build.sbt
@@ -10,7 +10,7 @@ scalaVersion := "2.11.4"
libraryDependencies += "com.github.japgolly.scalajs-react" %%% "core" % "0.5.1"
-jsDependencies += "org.webjars" % "react" % "0.11.1" / "react-with-addons.js" commonJSName "React"
+
libraryDependencies += "com.lihaoyi" %%% "upickle" % "0.2.5"