diff --git a/.gitignore b/.gitignore index d283ea78a..3ff004e10 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ vendor/ /.idea .ruby-version .sass-cache/ +.ivy2/ +.sbt/ +target \ No newline at end of file diff --git a/README.md b/README.md index 2e56188a7..6a05de01c 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,11 @@ bin/serve bundle exec jekyll serve --incremental ``` +### For ScalaJs Development +``` +sbt ~fastOptJS +``` + ## Viewing the site Regardless of your method of running Jekyll, the generated site is available at `http://localhost:4000`. diff --git a/_config.yml b/_config.yml index 8ec004b22..4405cb398 100644 --- a/_config.yml +++ b/_config.yml @@ -9,6 +9,8 @@ highlighter: exclude: - bundle-vendor/ - bin/ + - js-src/ + - project/ - blog/README.md - training/README.md - README.md @@ -19,6 +21,7 @@ exclude: - vendor - Procfile - Rakefile + - docker-compose.yml future: true diff --git a/_includes/footer.html b/_includes/footer.html index 9356da31a..99fc0d17e 100644 --- a/_includes/footer.html +++ b/_includes/footer.html @@ -51,6 +51,7 @@ + diff --git a/bin/build-js b/bin/build-js new file mode 100644 index 000000000..fc5ccc0bf --- /dev/null +++ b/bin/build-js @@ -0,0 +1,3 @@ +#!/bin/bash -x +command -v docker-compose >/dev/null 2>&1 || { echo >&2 "Please install Docker Compose: https://docs.docker.com/compose/install/"; exit 1; } +docker-compose run js-build sbt fullOptJS diff --git a/bin/serve b/bin/serve index 9e05fa696..5cabd58ec 100755 --- a/bin/serve +++ b/bin/serve @@ -1,3 +1,4 @@ #!/bin/bash command -v docker-compose >/dev/null 2>&1 || { echo >&2 "Please install Docker Compose: https://docs.docker.com/compose/install/"; exit 1; } -docker-compose run --service-ports scala-lang jekyll serve --incremental +docker-compose up +docker-compose stop \ No newline at end of file diff --git a/build.sbt b/build.sbt new file mode 100644 index 000000000..e71f15f20 --- /dev/null +++ b/build.sbt @@ -0,0 +1,14 @@ +name := "scala-lang" + +organization in ThisBuild := "org.scalalang" +version in ThisBuild := "0.1" +scalaVersion in ThisBuild := "2.12.6" +scalacOptions in ThisBuild ++= Seq( + "-feature", + "-deprecation" +) + +lazy val functions = project in file("js-src/functions") + +lazy val root: Project = project.in(file(".")) + .aggregate(functions) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 516153962..ac035af2e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,10 @@ version: "2" services: + js-build: + image: hseeberger/scala-sbt:latest + volumes: + - $PWD:/root + command: sbt ~fastOptJS scala-lang: image: jekyll/jekyll:latest volumes: @@ -9,4 +14,5 @@ services: - 4000:4000 - 35729:35729 - 3000:3000 - - 80:4000 \ No newline at end of file + - 80:4000 + command: jekyll serve --incremental \ No newline at end of file diff --git a/js-src/functions/build.sbt b/js-src/functions/build.sbt new file mode 100644 index 000000000..d06ea1803 --- /dev/null +++ b/js-src/functions/build.sbt @@ -0,0 +1,15 @@ +enablePlugins(ScalaJSPlugin) + +name := "functions" + +libraryDependencies ++= Seq( + "org.scala-js" %%% "scalajs-dom" % Versions.Dom, + "org.querki" %%% "jquery-facade" % Versions.JQuery +) + +// move our output folder to static +artifactPath in(Compile, fastOptJS) := baseDirectory.value / ".." / ".." / "resources" / "js" / s"scala-${name.value}.js" +artifactPath in(Compile, fullOptJS) := baseDirectory.value / ".." / ".." / "resources" / "js" / s"scala-${name.value}.js" + +scalaJSUseMainModuleInitializer := true +scalaJSLinkerConfig ~= { _.withSourceMap(false) } \ No newline at end of file diff --git a/js-src/functions/src/main/scala/org/scalalang/DownloadLinks.scala b/js-src/functions/src/main/scala/org/scalalang/DownloadLinks.scala new file mode 100644 index 000000000..63cf14c31 --- /dev/null +++ b/js-src/functions/src/main/scala/org/scalalang/DownloadLinks.scala @@ -0,0 +1,45 @@ +package org.scalalang + +import org.querki.jquery._ +import org.scalajs.dom.{Element, document} +import org.scalalang.utils.{JsUtils, OS} + +/** + * This updates our download links based on the OS of the client + */ +object DownloadLinks { + + def apply(): Unit = { + setupBinariesElement() + setupMainDownload() + } + + private def setupBinariesElement(): Unit = JsUtils.findElement("#download-binaries").foreach((binariesElmnt: JQuery) => { + val os: OS = OS() + val osLabel: String = os.label + + var anchor: Element = document.getElementById("#link-main-unixsys") + if (os == OS.Windows) { + anchor = document.getElementById("#link-main-windows") + } + if (anchor == null) { + anchor = document.getElementById("#link-main-one4all") + } + val link: String = anchor.getAttribute("href") + + binariesElmnt.attr("href", link).addClass(osLabel) + $("#users-os").text(osLabel) + }) + + private def setupMainDownload(): Unit = JsUtils.findElement(".main-download").foreach(_ => { + val osLabel: String = OS().label + + val intelliJlink: String = $("#intellij-" + osLabel).text() + val sbtLink: String = $("#sbt-" + osLabel).text() + val stepOneContent: String = $("#stepOne-" + osLabel).html() + + $("#download-intellij-link").attr("href", intelliJlink) + $("#download-sbt-link").attr("href", sbtLink) + $("#download-step-one").html(stepOneContent) + }) +} diff --git a/js-src/functions/src/main/scala/org/scalalang/FunctionsApp.scala b/js-src/functions/src/main/scala/org/scalalang/FunctionsApp.scala new file mode 100644 index 000000000..24f873101 --- /dev/null +++ b/js-src/functions/src/main/scala/org/scalalang/FunctionsApp.scala @@ -0,0 +1,19 @@ +package org.scalalang + +import org.querki.jquery._ +import org.scalajs.dom.document + +/** + * This is the main entry point for our application + */ +object FunctionsApp { + def main(args: Array[String]): Unit = { + $(document).ready(() => { + println("Dom Ready") + + Tooltip() + DownloadLinks() + PositionMarker() + }) + } +} \ No newline at end of file diff --git a/js-src/functions/src/main/scala/org/scalalang/PositionMarker.scala b/js-src/functions/src/main/scala/org/scalalang/PositionMarker.scala new file mode 100644 index 000000000..9658f4065 --- /dev/null +++ b/js-src/functions/src/main/scala/org/scalalang/PositionMarker.scala @@ -0,0 +1,37 @@ +package org.scalalang + +import org.querki.jquery._ +import org.scalajs.dom.window +import org.scalalang.utils.JsUtils + +/** + * This renders / updates the position marker on the front page + */ +object PositionMarker { + + private val imageWidth: Int = 1680 + + // where our position should be on the image + private val targetX: Int = 1028 + private val targetY: Int = 290 + + def apply(): Unit = JsUtils.findElement("#position-marker") + .foreach((pointer: JQuery) => { + val updater: () => Unit = updatePointer(pointer) + + // register on window resize + $(window).resize(updater) + + // initialize + pointer.css("top", targetY) + updater() + }) + + private def updatePointer(pointer: JQuery): () => Unit = () => { + val windowWidth: Double = $(window).width() + + val xScale: Double = windowWidth / imageWidth + + pointer.css("left", (targetX * xScale).toInt) + } +} diff --git a/js-src/functions/src/main/scala/org/scalalang/Tooltip.scala b/js-src/functions/src/main/scala/org/scalalang/Tooltip.scala new file mode 100644 index 000000000..80a954da3 --- /dev/null +++ b/js-src/functions/src/main/scala/org/scalalang/Tooltip.scala @@ -0,0 +1,40 @@ +package org.scalalang + +import org.querki.jquery._ +import org.scalajs.dom.Element + +import scala.scalajs.js + +/** + * This renders tooltips for any .masterTooltip class element + */ +object Tooltip { + def apply(): Unit = { + $(".masterTooltip") + .hover( + (tooltip: Element) => { + // make sure we have a title + $(tooltip).attr("title").toOption.foreach((title: String) => { + // create our tooltip and place it on the body + $("

") + .text(title) + .appendTo("body") + .fadeIn("slow") + }) + }, + () => { + // remove our tooltip when we mouse off + $(".tooltip").remove() + } + ) + .mousemove((e: JQueryEventObject) => { + val mouseX: Int = e.pageX + 20 //Get X coordinates + val mouseY: Int = e.pageY + 10 //Get Y coordinates + + $(".tooltip").css(js.Dictionary[js.Any]( + "left" -> mouseX, + "top" -> mouseY + )) + }) + } +} diff --git a/js-src/functions/src/main/scala/org/scalalang/utils/JsUtils.scala b/js-src/functions/src/main/scala/org/scalalang/utils/JsUtils.scala new file mode 100644 index 000000000..e34651f1f --- /dev/null +++ b/js-src/functions/src/main/scala/org/scalalang/utils/JsUtils.scala @@ -0,0 +1,14 @@ +package org.scalalang.utils + +import org.querki.jquery._ + +object JsUtils { + /** + * @param element the element we wish to find + * @return the returned jquery element will have > 1 elements + */ + @inline + def findElement(element: ElementDesc): Option[JQuery] = { + Option($(element)).filter(_.length > 0) + } +} diff --git a/js-src/functions/src/main/scala/org/scalalang/utils/OS.scala b/js-src/functions/src/main/scala/org/scalalang/utils/OS.scala new file mode 100644 index 000000000..f952be2a6 --- /dev/null +++ b/js-src/functions/src/main/scala/org/scalalang/utils/OS.scala @@ -0,0 +1,32 @@ +package org.scalalang.utils + +import org.scalajs.dom.window + +/** + * Find which OS our client is running + */ +sealed abstract class OS(val navigator: String, val label: String) + +object OS { + + case object Windows extends OS("Win", "windows") + + case object Mac extends OS("Mac", "osx") + + case object Linux extends OS("Linux", "linux") + + case object Unix extends OS("X11", "unix") + + def apply(): OS = { + val appVersion: String = window.navigator.appVersion + val default: OS = Linux + + val os: OS = Array(Windows, Mac, Linux, Unix) + .find(os => appVersion.contains(os.navigator)) + .getOrElse(default) + + println("OS: " + os) + + os + } +} \ No newline at end of file diff --git a/project/Versions.scala b/project/Versions.scala new file mode 100644 index 000000000..32bb8a215 --- /dev/null +++ b/project/Versions.scala @@ -0,0 +1,8 @@ +/** + * Shared Versions + */ +object Versions { + val Dom = "0.9.2" + + val JQuery = "1.2" +} \ No newline at end of file diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 000000000..16eecf57c --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.1.6 \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 000000000..196b49299 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,2 @@ +// Cross project compilation +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.24") \ No newline at end of file diff --git a/resources/js/.gitignore b/resources/js/.gitignore new file mode 100644 index 000000000..074fb6891 --- /dev/null +++ b/resources/js/.gitignore @@ -0,0 +1 @@ +scala-functions.* \ No newline at end of file diff --git a/resources/js/functions.js b/resources/js/functions.js index 1178035fd..4faa11ef6 100644 --- a/resources/js/functions.js +++ b/resources/js/functions.js @@ -1,6 +1,3 @@ ---- ---- - // Sliding Panel and scala in a nutshell $(document).ready(function() { $('.navigation-panel-button,.navigation-fade-screen,.navigation-panel-close').on('click touchstart', function(e) { @@ -38,29 +35,6 @@ $(document).ready(function() { }); }); -// Tooltip -$(document).ready(function() { - // Tooltip only Text - $('.masterTooltip').hover(function(){ - // Hover over code - var title = $(this).attr('title'); - $(this).data('tipText', title).removeAttr('title'); - $('

') - .text(title) - .appendTo('body') - .fadeIn('slow'); - }, function() { - // Hover out code - $(this).attr('title', $(this).data('tipText')); - $('.tooltip').remove(); - }).mousemove(function(e) { - var mousex = e.pageX + 20; //Get X coordinates - var mousey = e.pageY + 10; //Get Y coordinates - $('.tooltip') - .css({ top: mousey, left: mousex }) - }); -}); - // Highlight $(document).ready(function() { hljs.configure({ @@ -248,77 +222,6 @@ $(document).ready(function() { } }); -// OS detection -function getOS() { - var osname = "linux"; - if (navigator.appVersion.indexOf("Win") != -1) osname = "windows"; - if (navigator.appVersion.indexOf("Mac") != -1) osname = "osx"; - if (navigator.appVersion.indexOf("Linux") != -1) osname = "linux"; - if (navigator.appVersion.indexOf("X11") != -1) osname = "unix"; - return osname; -} - -$(document).ready(function() { - if ($(".main-download").length) { - var os = getOS(); - var intelliJlink = $("#intellij-" + os).text(); - var sbtLink = $("#sbt-" + os).text(); - var stepOneContent = $("#stepOne-" + os).html() - $("#download-intellij-link").attr("href", intelliJlink); - $("#download-sbt-link").attr("href", sbtLink); - $("#download-step-one").html(stepOneContent); - } -}); - - -$(document).ready(function() { - - var os = getOS(); - if (os == "Unknown OS") os = "UNIX"; - - var osLabel = os.replace(/\s/g, '').toLowerCase(); - - // Do not do any of the following if we're not on a download page - // Otherwise a TypeError is raised and disables all other scripts on the page - if ($("#download-binaries").length == 0) - return; - - /*$("#download-button, #getting-started-popup").click(function() { - $("#getting-started-popup").toggleClass("open"); - });*/ - - var anchor = document.getElementById("#link-main-unixsys"); - if (os == "windows") { - anchor = document.getElementById("#link-main-windows"); - } - if (anchor == null) anchor = document.getElementById("#link-main-one4all"); - var link = anchor.getAttribute("href"); - - $("#download-binaries").attr("href", link).addClass(osLabel); - $("#users-os").text(os); -}); - - -var image = { width: 1680, height: 1100 }; -var target = { x: 1028, y: 290 }; - -var pointer = $('#position-marker'); - -$(document).ready(updatePointer); -$(window).resize(updatePointer); - -function updatePointer() { - - var windowWidth = $(window).width(); - var windowHeight = $(window).height(); - - var xScale = windowWidth / image.width; - var yScale = windowHeight / image.height; - - pointer.css('top', (target.y)); - pointer.css('left', (target.x) * xScale); -} - // TRAININGS $(document).ready(function() { var MONTH_NAMES = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];