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._
case class Tree[T](name: T, children: Vector[Tree[T]])
@JSExport
object Controller{
def munge(name: String) = {
name.replace(" ", "")
}
def addClass(el: dom.HTMLElement, cls: String) = {
removeClass(el, cls)
el.className = el.className + " " + cls
}
def removeClass(el: dom.HTMLElement, cls: String) = {
el.className = el.className.split(' ')
.iterator
.filter(_ != cls)
.mkString(" ")
}
def toggleClass(el: dom.HTMLElement, cls: String) = {
val frags = el.className.split(' ')
if (!frags.contains(cls)) addClass(el, cls)
else removeClass(el, cls)
}
@JSExport
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], depth: Int): Tree[(dom.HTMLElement, Int)] = {
val curr =
li(paddingLeft := "15px")(
a(
t.name,
href:="#"+munge(t.name),
cls:="menu-item"
)
)
val originalI = i
i += 1
val children = t.children.map(recurse(_, depth + 1))
Tree(
(
curr(ul(children.map(_.name._1))).render,
originalI
),
children
)
}
val Seq(main, menu, layout, menuLink) = Seq(
"main", "menu", "layout", "menuLink"
).map(dom.document.getElementById)
val snippets = dom.document.getElementsByClassName("highlight-me")
snippets.foreach(js.Dynamic.global.hljs.highlightBlock(_))
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 = {
val menuItems = {
def rec(current: Tree[String]): Seq[String] = {
current.name +: current.children.flatMap(rec)
}
rec(structure).tail
}
menuItems.map(munge)
.map(dom.document.getElementById)
.map(offset(_, main))
.toVector
}
val domTrees = recurse(structure, 0).children
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)
)
).render
)
menuLink.onclick = (e: dom.MouseEvent) => {
toggleClass(layout, "active")
toggleClass(menu, "active")
toggleClass(menuLink, "active")
}
var scrolling = false
def start() ={
scrolling = false
val threshold = main.scrollTop + main.clientHeight
println("")
def walkTree(tree: Tree[(dom.HTMLElement, Int)]): Unit = {
val Tree((menuItem, index), children) = tree
val before = headers(index) < threshold
val next = children.lastOption
.fold(index)(_.name._2)
val win = before && headers.lift(next + 1).getOrElse(999999.0) > threshold
if (win){
removeClass(menuItem, "hide")
addClass(menuItem, "selected")
tree.children.foreach(walkTree)
}else{
addClass(menuItem, "hide")
removeClass(menuItem, "selected")
}
}
domTrees.map(walkTree)
}
main.onscroll = (e: dom.UIEvent) => if (!scrolling){
scrolling = true
dom.requestAnimationFrame((d: Double) => start())
}
}
def isElementInViewport(el: dom.HTMLElement) = {
val rect = el.getBoundingClientRect()
rect.top >= 0 && rect.bottom <= dom.innerHeight
}
}