summaryrefslogtreecommitdiff
path: root/examples/demos/Controller.scala
blob: d27c68ee2ed57f5f8ede1c56b04c87dd23031a86 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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())
      }
    }
  }
}