summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi@dropbox.com>2014-11-14 15:44:54 -0800
committerLi Haoyi <haoyi@dropbox.com>2014-11-14 15:44:54 -0800
commit64b283eb61f2c20e39e4c55e8696522569420028 (patch)
tree875fdb95af7991717c63cb45be3f00eb70d7408d
parentac06ede92a8be7a064e30364161d2610e547e988 (diff)
downloadhands-on-scala-js-64b283eb61f2c20e39e4c55e8696522569420028.tar.gz
hands-on-scala-js-64b283eb61f2c20e39e4c55e8696522569420028.tar.bz2
hands-on-scala-js-64b283eb61f2c20e39e4c55e8696522569420028.zip
lots of cleanip
-rw-r--r--book/src/main/scala/book/Main.scala4
-rw-r--r--book/src/main/scala/book/Utils.scala6
-rw-r--r--examples/demos/Controller.scala67
-rw-r--r--examples/demos/ScrollMenu.scala50
-rw-r--r--examples/demos/build.sbt4
5 files changed, 72 insertions, 59 deletions
diff --git a/book/src/main/scala/book/Main.scala b/book/src/main/scala/book/Main.scala
index 91360d5..da9bace 100644
--- a/book/src/main/scala/book/Main.scala
+++ b/book/src/main/scala/book/Main.scala
@@ -27,8 +27,8 @@ object Main {
}
val allNames = {
- def rec(n: Node): Seq[String] = {
- n.name +: n.children.flatMap(rec)
+ def rec(n: Tree[String]): Seq[String] = {
+ n.value +: n.children.flatMap(rec)
}
rec(sect.structure).toSet
}
diff --git a/book/src/main/scala/book/Utils.scala b/book/src/main/scala/book/Utils.scala
index 07f462c..ad41d18 100644
--- a/book/src/main/scala/book/Utils.scala
+++ b/book/src/main/scala/book/Utils.scala
@@ -34,7 +34,7 @@ object sect{
(h6(_, _, _), None)
)
- var structure = Node("root", mutable.Buffer.empty)
+ var structure = Tree[String]("root", mutable.Buffer.empty)
val usedRefs = mutable.Set.empty[String]
@@ -49,7 +49,7 @@ object sect{
}
case class sect(name: String, subname: String = ""){
sect.indent += 1
- val newNode = Node(name, mutable.Buffer.empty)
+ val newNode = Tree[String](name, mutable.Buffer.empty)
val (headerWrap, contentWrap) = sect.headers(sect.indent-1)
sect.structure.children.append(newNode)
val prev = sect.structure
@@ -75,7 +75,7 @@ case class sect(name: String, subname: String = ""){
res
}
}
-case class Node(name: String, children: mutable.Buffer[Node])
+case class Tree[T](value: T, children: mutable.Buffer[Tree[T]])
object lnk{
val usedLinks = mutable.Set.empty[String]
def apply(name: String, url: String) = {
diff --git a/examples/demos/Controller.scala b/examples/demos/Controller.scala
index 9a11597..6fd7ac7 100644
--- a/examples/demos/Controller.scala
+++ b/examples/demos/Controller.scala
@@ -1,4 +1,4 @@
-
+import acyclic.file
import scala.scalajs.js
import scala.scalajs.js.annotation.JSExport
import org.scalajs.dom
@@ -6,7 +6,7 @@ import org.scalajs.dom.extensions._
import scala.collection.mutable
import scalatags.JsDom.all._
-case class Tree[T](name: T, children: Vector[Tree[T]])
+
@JSExport
object Controller{
@@ -20,12 +20,12 @@ object Controller{
val structure = upickle.readJs[Tree[String]](upickle.json.readJs(data))
var i = 0
- def recurse(t: Tree[String], depth: Int): Tree[(dom.HTMLElement, Int, Int)] = {
+ def recurse(t: Tree[String], depth: Int): Tree[MenuNode] = {
val curr =
li(
a(
- t.name,
- href:="#"+munge(t.name),
+ t.value,
+ href:="#"+munge(t.value),
cls:="menu-item"
)
)
@@ -33,10 +33,10 @@ object Controller{
i += 1
val children = t.children.map(recurse(_, depth + 1))
Tree(
- (
- curr(ul(paddingLeft := "15px",children.map(_.name._1))).render,
+ MenuNode(
+ curr(ul(paddingLeft := "15px",children.map(_.value.frag))).render,
originalI,
- if (children.length > 0) children.map(_.name._3).max else originalI + 1
+ if (children.length > 0) children.map(_.value.end).max else originalI + 1
),
children
)
@@ -57,7 +57,7 @@ object Controller{
val menuItems = {
def rec(current: Tree[String]): Seq[String] = {
- current.name +: current.children.flatMap(rec)
+ current.value +: current.children.flatMap(rec)
}
rec(structure).tail
}
@@ -68,15 +68,17 @@ object Controller{
}
println(headers)
- val domTrees = structure.children.map(recurse(_, 0))
+
+ val domTrees = structure.children.map(recurse(_, 0))
+ val scrollSpy = new ScrollSpy(headers, domTrees)
menu.appendChild(
div(cls:="pure-menu pure-menu-open")(
a(cls:="pure-menu-heading", href:="#")(
"Contents"
),
ul(cls:="menu-item-list")(
- domTrees.map(_.name._1)
+ domTrees.map(_.value.frag)
)
).render
)
@@ -86,50 +88,13 @@ object Controller{
menuLink.classList.toggle("active")
}
- var scrolling = false
- var lastSelected: dom.HTMLElement = null
- def start() ={
- scrolling = false
- val threshold = main.scrollTop + main.clientHeight
- def walkTree(tree: Tree[(dom.HTMLElement, Int, Int)]): Boolean = {
- val Tree((menuItem, index, next), children) = tree
- val before = headers(index) < threshold
- val after = (next >= headers.length) || headers(next) > threshold
- val win = before && after
- if (win){
- menuItem.classList.remove("hide")
- var winFound = false
- for(c <- tree.children){
- val newWinFound = walkTree(c)
- if (!winFound) c.name._1.classList.add("selected")
- else c.name._1.classList.remove("selected")
- winFound = winFound | newWinFound
- }
- if (!winFound) {
- tree.children.foreach(_.name._1.classList.remove("selected"))
- if (lastSelected != null)
- lastSelected.children(0).classList.remove("pure-menu-selected")
- menuItem.children(0).classList.add("pure-menu-selected")
- lastSelected = menuItem
- }
- }else{
- menuItem.classList.add("hide")
- menuItem.classList.remove("selected")
- }
- win
- }
- domTrees.map(walkTree)
- }
- main.onscroll = (e: dom.UIEvent) => if (!scrolling){
- scrolling = true
- dom.requestAnimationFrame((d: Double) => start())
+ main.onscroll = (e: dom.UIEvent) => {
+ scrollSpy(main.scrollTop + main.clientHeight)
}
}
def isElementInViewport(el: dom.HTMLElement) = {
val rect = el.getBoundingClientRect()
rect.top >= 0 && rect.bottom <= dom.innerHeight
}
-
-
-} \ No newline at end of file
+}
diff --git a/examples/demos/ScrollMenu.scala b/examples/demos/ScrollMenu.scala
new file mode 100644
index 0000000..ccab4e9
--- /dev/null
+++ b/examples/demos/ScrollMenu.scala
@@ -0,0 +1,50 @@
+import acyclic.file
+import org.scalajs.dom
+
+case class Tree[T](value: T, children: Vector[Tree[T]])
+
+case class MenuNode(frag: dom.HTMLElement, start: Int, end: Int)
+
+/**
+ * High performance scrollspy to
+ */
+class ScrollSpy(headers: Vector[Double], domTrees: Seq[Tree[MenuNode]]){
+ var scrolling = false
+ var lastSelected: dom.HTMLElement = null
+ def apply(threshold: Double) = if (!scrolling){
+ scrolling = true
+ dom.requestAnimationFrame((d: Double) => start(threshold))
+ }
+ def start(threshold: Double) = {
+ scrolling = false
+ def walkTree(tree: Tree[MenuNode]): Boolean = {
+ val Tree(MenuNode(menuItem, index, next), children) = tree
+ val before = headers(index) < threshold
+ val after = (next >= headers.length) || headers(next) > threshold
+ val win = before && after
+ if (win){
+ menuItem.classList.remove("hide")
+ var winFound = false
+
+ for(c <- tree.children){
+ val newWinFound = walkTree(c)
+ if (!winFound) c.value.frag.classList.add("selected")
+ else c.value.frag.classList.remove("selected")
+ winFound = winFound | newWinFound
+ }
+ if (!winFound) {
+ tree.children.foreach(_.value.frag.classList.remove("selected"))
+ if (lastSelected != null)
+ lastSelected.children(0).classList.remove("pure-menu-selected")
+ menuItem.children(0).classList.add("pure-menu-selected")
+ lastSelected = menuItem
+ }
+ }else{
+ menuItem.classList.add("hide")
+ menuItem.classList.remove("selected")
+ }
+ win
+ }
+ domTrees.map(walkTree)
+ }
+} \ No newline at end of file
diff --git a/examples/demos/build.sbt b/examples/demos/build.sbt
index 040f9fd..fb79984 100644
--- a/examples/demos/build.sbt
+++ b/examples/demos/build.sbt
@@ -8,9 +8,7 @@ version := "0.1-SNAPSHOT"
scalaVersion := "2.11.4"
-libraryDependencies += "com.github.japgolly.scalajs-react" %%% "core" % "0.5.1"
-
-
+libraryDependencies += "com.lihaoyi" %% "acyclic" % "0.1.2" % "provided"
libraryDependencies += "com.lihaoyi" %%% "upickle" % "0.2.5"