summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi@dropbox.com>2014-11-11 21:32:25 -0800
committerLi Haoyi <haoyi@dropbox.com>2014-11-11 21:32:25 -0800
commitdab933c342d755086253b1465a04caeeaa2af823 (patch)
tree62019986ef2becf02b9848ed983eadcd4837a5d2
parent43795c30a7295310b47885b3eacca9fd9af33343 (diff)
downloadhands-on-scala-js-dab933c342d755086253b1465a04caeeaa2af823.tar.gz
hands-on-scala-js-dab933c342d755086253b1465a04caeeaa2af823.tar.bz2
hands-on-scala-js-dab933c342d755086253b1465a04caeeaa2af823.zip
Pure Scala!
-rwxr-xr-xbook/src/main/resources/js/ui.js97
-rw-r--r--book/src/main/scala/book/Book.scala47
-rw-r--r--build.sbt4
-rw-r--r--examples/demos/Controller.scala130
-rw-r--r--examples/demos/build.sbt4
5 files changed, 147 insertions, 135 deletions
diff --git a/book/src/main/resources/js/ui.js b/book/src/main/resources/js/ui.js
deleted file mode 100755
index ba79579..0000000
--- a/book/src/main/resources/js/ui.js
+++ /dev/null
@@ -1,97 +0,0 @@
-document.addEventListener("DOMContentLoaded", function(){
- console.log("HIGHLIGHTING")
-
- var layout = document.getElementById('layout'),
- menu = document.getElementById('menu'),
- menuLink = document.getElementById('menuLink');
-
- function toggleClass(element, className) {
- var classes = element.className.split(/\s+/),
- length = classes.length,
- i = 0;
-
- for(; i < length; i++) {
- if (classes[i] === className) {
- classes.splice(i, 1);
- break;
- }
- }
- // The className is not found
- if (length === classes.length) {
- classes.push(className);
- }
-
- element.className = classes.join(' ');
- }
-
- menuLink.onclick = function (e) {
- var active = 'active';
-
- e.preventDefault();
- toggleClass(layout, active);
- toggleClass(menu, active);
- toggleClass(menuLink, active);
- };
-
-
- var snippets = document.getElementsByClassName("highlight-me");
- for(var i = 0; i < snippets.length; i++){
- hljs.highlightBlock(snippets[i])
- }
-
-
-
-
- // Cache selectors
- var lastId = -1;
- var main = document.getElementById("main");
-
- scrollItems = document.getElementsByClassName("menu-item");
-
- scrollHeaders = []
-
- for(var i = 0; i < scrollItems.length; i++){
- scrollHeaders.push(
- document.getElementById(
- scrollItems[i].getAttribute("href").substring(1)
- )
- )
- }
-
-
- function isElementInViewport (el) {
- var rect = el.getBoundingClientRect();
-
- return (
- rect.top >= 0 &&
- rect.left >= 0 &&
- rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
- rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
- );
- }
- main.addEventListener("scroll", function(){
- // Get container scroll position
- var fromTop = main.scrollTop;
-
- // Get id of current scroll item
- for(var i = scrollItems.length - 1; i >= 0; i--){
- if (scrollHeaders[i].offsetTop < fromTop + 100 /*fudge factor*/){
- if (lastId != i) {
- if (lastId != -1) {
- scrollItems[lastId].parentElement.className = scrollItems[lastId].parentElement.className.replace(
- " pure-menu-selected",
- ""
- );
- }
- scrollItems[i].parentElement.className = scrollItems[i].parentElement.className + " pure-menu-selected"
- if (!isElementInViewport(scrollItems[i].parentElement)){
- scrollItems[i].parentElement.scrollIntoView(lastId > i)
- }
-
- lastId = i
- }
- break;
- }
- }
- });
-});
diff --git a/book/src/main/scala/book/Book.scala b/book/src/main/scala/book/Book.scala
index c6c9c2e..ea57945 100644
--- a/book/src/main/scala/book/Book.scala
+++ b/book/src/main/scala/book/Book.scala
@@ -25,7 +25,6 @@ object Book {
"META-INF/resources/webjars/font-awesome/4.2.0/fonts/fontawesome-webfont.ttf",
"META-INF/resources/webjars/font-awesome/4.2.0/fonts/fontawesome-webfont.woff",
"css/side-menu.css",
- "js/ui.js",
"example-fastopt.js",
"webpage/weather.js",
"favicon.svg",
@@ -52,24 +51,8 @@ object Book {
}
val txt = Index()
- val contentBar = {
- def rec(current: Node, depth: Int): Seq[Frag] = {
- println("\t"*depth + current.name)
- Seq(
- li(
- a(
- current.name,
- href:="#"+sect.munge(current.name),
- paddingLeft := s"${depth * 10 + 10}px",
- cls := "menu-item" + (if (depth == 1) " menu-item-divided " else "")
- )
- )
- ) ++ current.children.flatMap(rec(_, depth + 1))
- }
+ val data = upickle.write(sect.structure)
- println("TABLE OF CONTENTS")
- rec(sect.structure, 0)
- }
val site = Seq(
raw("<!doctype html>"),
html(
@@ -80,27 +63,19 @@ object Book {
tags2.title("Hands-on Scala.js"),
includes
),
-
- div(id:="layout")(
- a(href:="#menu", id:="menuLink", cls:="menu-link")(
- span
+ body(
+ onload:=s"Controller().main($data)",
+ div(id:="layout")(
+ a(href:="#menu", id:="menuLink", cls:="menu-link")(
+ span
+ ),
+ div(id:="menu")
),
-
- div(id:="menu")(
- div(cls:="pure-menu pure-menu-open")(
- a(cls:="pure-menu-heading", href:="#")(
- "Contents"
- ),
- ul(cls:="menu-item-list")(
- contentBar
- )
+ div(id:="main",
+ div(id:="main-box")(
+ txt
)
)
- ),
- div(id:="main",
- div(id:="main-box")(
- txt
- )
)
)
).render
diff --git a/build.sbt b/build.sbt
index c566cab..a2012d5 100644
--- a/build.sbt
+++ b/build.sbt
@@ -39,7 +39,8 @@ lazy val book = Project(
"org.webjars" % "font-awesome" % "4.2.0",
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"org.scala-lang" % "scala-compiler" % scalaVersion.value,
- "org.eclipse.jgit" % "org.eclipse.jgit" % "3.5.1.201410131835-r"
+ "org.eclipse.jgit" % "org.eclipse.jgit" % "3.5.1.201410131835-r",
+ "com.lihaoyi" %%% "upickle" % "0.2.5"
),
(resources in Compile) += {
(fastOptJS in (demos, Compile)).value
@@ -67,7 +68,6 @@ lazy val book = Project(
addCompilerPlugin("com.lihaoyi" %% "acyclic" % "0.1.2")
)
-
lazy val demos = project.in(file("examples/demos"))
lazy val simple = project.in(file("examples/crossBuilds/simple"))
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())
+ }
+ }
+ }
+}
diff --git a/examples/demos/build.sbt b/examples/demos/build.sbt
index 20b9fca..5374c30 100644
--- a/examples/demos/build.sbt
+++ b/examples/demos/build.sbt
@@ -6,6 +6,10 @@ version := "0.1-SNAPSHOT"
scalaVersion := "2.11.4"
+libraryDependencies += "com.scalarx" %%% "scalarx" % "0.2.6"
+
+libraryDependencies += "com.lihaoyi" %%% "upickle" % "0.2.5"
+
libraryDependencies += "org.scala-lang.modules.scalajs" %%% "scalajs-dom" % "0.6"
libraryDependencies += "com.scalatags" %%% "scalatags" % "0.4.2" \ No newline at end of file