summaryrefslogblamecommitdiff
path: root/examples/demos/Controller.scala
blob: 6e7df42db37413953c34224d7201834d3532a551 (plain) (tree)
1
2
3
4
5
6
7
8
9





                                           


                                                                                 
 
 
                                                      





                             
                                                    





                                                                         

                                                       

                                               



                                          
                                                                           
             









                                                                  
            

                                                          

     


                                                
 



                                                                      





                                                                                         
                                                       






                                                       
                 
     
 
 
                                        
                                  

          



                                               
     
 









                                                          
         








                                         
       
             

     



                                                   
 
 

                                                      



                                                             
               

                                                   

                        

                                                                  

       







                                                         
                                                                
 











                                                                 
       


                        
     
 




                                                     
                              




         
import scala.scalajs.js
import scala.scalajs.js.annotation.JSExport
import org.scalajs.dom
import org.scalajs.dom.extensions._
import scala.collection.mutable
import japgolly.scalajs.react._ // React

import vdom.ReactVDom.all._     // Scalatags html & css (div, h1, textarea, etc.)


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(' ').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[(Tag, Int)] = {
      val curr =
        li(paddingLeft := s"${depth * 15}px")(
          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 -> 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(_))

    val headers = {
      def offset(el: dom.HTMLElement, parent: dom.HTMLElement): Double = {
        if (el == parent) 0
        else el.offsetTop + offset(el.offsetParent.asInstanceOf[dom.HTMLElement], parent)
      }
      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 menuBar = React.renderComponent(
      Menu(recurse(structure, 0)),
      menu
    )
    menuLink.onclick = (e: dom.MouseEvent) => {
      toggleClass(layout, "active")
      toggleClass(menu, "active")
      toggleClass(menuLink, "active")
    }

    var x = -1
    def start() =
      x = dom.setTimeout(() => {
        x = -1
        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)

      }, 100)

    main.onscroll = (e: dom.UIEvent) => {
      if (x != -1){
        dom.clearTimeout(x)
        s
      }
      start()
    }
  }
  def isElementInViewport(el: dom.HTMLElement) = {
    val rect = el.getBoundingClientRect()
    rect.top >= 0 && rect.bottom <= dom.innerHeight
  }



  val Menu = ReactComponentB[Tree[(Tag, Int)]]("Menu")
                            .getInitialState(_ => 0)
                            .render{ (structure, _, index) =>

    val contentList = {
      var i = 0
      val winArray = new js.Array[Boolean](0)
      def rec1(current: Tree[(Tag, Int)]): Unit = {
        val initialI = i
        i += 1
        current.children.foreach(rec1)
        winArray(current.name._2) = i >= index && initialI < index
      }

      val output = new js.Array[Tag](0)
      def rec(current: Tree[(Tag, Int)],
              classes: String): Unit = {


        val winIndex = current.children.indexWhere { x =>
          winArray(x.name._2)
        }
        val (before, after) = current.children.splitAt(winIndex)

        val (tag, currIndex) = current.name

        val win = winArray(currIndex)

        val frag = tag(
          cls:=classes + (if (win) " pure-menu-selected" else "")
        )

        output.push(frag)

        before.foreach(rec(_, "lined"))
        after.foreach(rec(_, if (!win) "hide" else ""))
      }
      rec1(structure)
      rec(structure, "")
      output
    }

    val frag = div(cls:="pure-menu  pure-menu-open")(
      a(cls:="pure-menu-heading", href:="#")(
        "Contents"
      ),
      ul(cls:="menu-item-list")(
        contentList.drop(1):_*
      )
    )
    frag
  }.build
}