diff options
author | Li Haoyi <haoyi@dropbox.com> | 2014-11-11 21:32:25 -0800 |
---|---|---|
committer | Li Haoyi <haoyi@dropbox.com> | 2014-11-11 21:32:25 -0800 |
commit | dab933c342d755086253b1465a04caeeaa2af823 (patch) | |
tree | 62019986ef2becf02b9848ed983eadcd4837a5d2 /examples/demos/Controller.scala | |
parent | 43795c30a7295310b47885b3eacca9fd9af33343 (diff) | |
download | hands-on-scala-js-dab933c342d755086253b1465a04caeeaa2af823.tar.gz hands-on-scala-js-dab933c342d755086253b1465a04caeeaa2af823.tar.bz2 hands-on-scala-js-dab933c342d755086253b1465a04caeeaa2af823.zip |
Pure Scala!
Diffstat (limited to 'examples/demos/Controller.scala')
-rw-r--r-- | examples/demos/Controller.scala | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/examples/demos/Controller.scala b/examples/demos/Controller.scala new file mode 100644 index 0000000..d27c68e --- /dev/null +++ b/examples/demos/Controller.scala @@ -0,0 +1,130 @@ + +import scala.scalajs.js +import scala.scalajs.js.annotation.JSExport +import org.scalajs.dom +import org.scalajs.dom.extensions._ +import scala.collection.mutable +import scalatags.JsDom.all._ +import rx._ +import util.{Success, Failure} +case class Node(name: String, children: mutable.Buffer[Node]) +@JSExport +object Controller{ + + def munge(name: String) = { + name.replace(" ", "") + } + def toggleClass(el: dom.HTMLElement, cls: String) = { + val frags = el.className.split(' ') + if (!frags.contains(cls)) el.className = el.className + " " + cls + else el.className = el.className.split(' ').filter(_ != cls).mkString(" ") + } + @JSExport + def main(data: scala.scalajs.js.Any) = { + + val structure = upickle.readJs[Node](upickle.json.readJs(data)) + + val main = dom.document.getElementById("main") + val menu = dom.document.getElementById("menu") + + val layout = dom.document.getElementById("layout") + val menuLink = dom.document.getElementById("menuLink") + val snippets = dom.document.getElementsByClassName("highlight-me") + + snippets.foreach(js.Dynamic.global.hljs.highlightBlock(_)) + + val contentBar = { + def rec(current: Node, depth: Int): Seq[dom.HTMLLIElement] = { + println("\t"*depth + current.name) + val myCls = + "menu-item" + + (if (depth == 1) " menu-item-divided" else "") + + val frag = + li( + a( + current.name, + href:="#"+munge(current.name), + paddingLeft := s"${depth * 10 + 10}px", + cls:=myCls + ) + ).render + + frag +: current.children.flatMap(rec(_, depth + 1)) + } + structure.children.flatMap(rec(_, 0)) + } + def menuItems = { + def rec(current: Node): Seq[String] = { + current.name +: current.children.flatMap(rec) + } + rec(structure).tail + } + val frag = div(cls:="pure-menu pure-menu-open")( + a(cls:="pure-menu-heading", href:="#")( + "Contents" + ), + ul(cls:="menu-item-list")( + contentBar + ) + ) + menu.appendChild(frag.render) + + def offset(el: dom.HTMLElement, parent: dom.HTMLElement): Double = { + if (el == parent) 0 + else el.offsetTop + offset(el.offsetParent.asInstanceOf[dom.HTMLElement], parent) + } + val headers = menuItems.map(munge) + .map(dom.document.getElementById) + .map(offset(_, main)) + .toArray + + scrollSpy(main, headers, contentBar) + + menuLink.onclick = (e: dom.MouseEvent) => { + toggleClass(layout, "active") + toggleClass(menu, "active") + toggleClass(menuLink, "active") + }; + } + + + + def scrollSpy(main: dom.HTMLElement, + headers: Seq[Double], + contentBar: Seq[dom.HTMLElement]) = { + def isElementInViewport(el: dom.HTMLElement) = { + val rect = el.getBoundingClientRect() + rect.top >= 0 && rect.bottom <= dom.innerHeight + } + + 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 - 1 + if (index != lastIndex){ + if (!isElementInViewport(contentBar(index))) { + contentBar(index).scrollIntoView(lastIndex > index) + } + if (lastIndex != -1) + toggleClass(contentBar(lastIndex), "pure-menu-selected") + toggleClass(contentBar(index), "pure-menu-selected") + lastIndex = index + } + } + run() + main.onscroll = (e: dom.UIEvent) => { + if (!scrolling){ + scrolling = true + dom.requestAnimationFrame((d: Double) => run()) + } + } + } +} |