diff --git a/build.sbt b/build.sbt index 6cb11ba6..6004785d 100644 --- a/build.sbt +++ b/build.sbt @@ -38,12 +38,24 @@ lazy val micrositeSettings = Seq( includeFilter in makeSite := "*.html" | "*.css" | "*.png" | "*.jpg" | "*.gif" | "*.js" | "*.swf" | "*.md" ) +val circeVersion = "0.5.2" + lazy val jsSettings = Seq( + scalaVersion := "2.11.8", scalaJSStage in Global := FastOptStage, parallelExecution := false, scalaJSUseRhino := false, requiresDOM := false, - jsEnv := NodeJSEnv().value + jsEnv := NodeJSEnv().value, + libraryDependencies ++= Seq( + "org.scala-js" %%% "scalajs-dom" % "0.9.0", + "be.doeraene" %%% "scalajs-jquery" % "0.9.0", + "com.lihaoyi" %%% "upickle" % "0.4.1", + "org.scala-exercises" %%% "evaluator-client" % "0.1.1-SNAPSHOT"), + resolvers ++= Seq(Resolver.url( + "bintray-sbt-plugin-releases", + url("https://dl.bintray.com/content/sbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns), + Resolver.sonatypeRepo("snapshots")) ) lazy val testSettings = diff --git a/js/src/main/scala/kazari/KazariPlugin.scala b/js/src/main/scala/kazari/KazariPlugin.scala new file mode 100644 index 00000000..e473d6de --- /dev/null +++ b/js/src/main/scala/kazari/KazariPlugin.scala @@ -0,0 +1,102 @@ +package kazari + +import org.scalajs.dom +import org.scalajs.dom._ + +import scala.scalajs.js.JSApp +import scala.scalajs.js.annotation.JSExport +import dom.ext.PimpedNodeList +import kazari.model.EvaluatorConfig +import org.scalaexercises.evaluator.Dependency +import org.scalaexercises.evaluator.{EvalResponse, EvaluatorClient} +import org.scalaexercises.evaluator.EvaluatorClient._ +import org.scalaexercises.evaluator.implicits._ +import org.scalaexercises.evaluator.EvaluatorResponses.EvaluationResponse +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.Future +import scala.util.{Failure, Success} + +@JSExport +object KazariPlugin extends JSApp with DOMHelper { + val codeExcludeClass = "code-exclude" + lazy val codeSnippets = document.querySelectorAll(s"code.language-scala:not(.$codeExcludeClass)") + val dependenciesMetaName = "evaluator-dependencies" + val resolversMetaName = "evaluator-resolvers" + + @JSExport + def main(): Unit = { } + + @JSExport + def decorateCode(config: EvaluatorConfig): Unit = { + val textSnippets = generateCodeTextSnippets() + + codeSnippets.zipWithIndex foreach { case (node, i) => + appendButton(node, "Evaluate", onClickFunction = (e: dom.MouseEvent) => { + val snippet = textSnippets.lift(i + 1) + + val client = new EvaluatorClient( + config.url, + config.authToken) + + snippet.foreach((s: String) => { + val evalResponse: Future[EvaluationResponse[EvalResponse]] = + client.api.evaluates( + dependencies = getDependenciesList(), + resolvers = getResolversList(), + code = snippet.getOrElse("")).exec + + evalResponse onComplete { + case Success(r) ⇒ + println(s"Connection to evaluator established: $r") + case Failure(f) ⇒ + println(s"Error while connecting with remote evaluator: $f") + } + }) + }) + } + } + + def generateCodeTextSnippets() = { + codeSnippets.map(_.textContent) + .scanLeft("")((currentItem, result) => currentItem + result) + } + + def getMetaContent(metaTagName: String): String = { + val metaTag = document.querySelector(s"meta[property=" + """"""" + s"$metaTagName" + """"""" + "]") + if (metaTag != null) { + metaTag.getAttribute("content") + } else { + "" + } + } + + def getDependenciesList(): List[Dependency] = { + val content = getMetaContent(dependenciesMetaName) + val elements = content.split(",") + + elements.foldRight(Seq[Dependency]()) { case (e, l) => + val split = e.split(";") + if (split.length == 3) { + l ++ Seq(Dependency(split(0), split(1), split(2))) + } else { + l + } + }.toList + } + + def getResolversList(): List[String] = { + val content = getMetaContent(resolversMetaName) + content.split(",").toList + } +} + +trait DOMHelper { + def appendButton[T](targetNode: dom.Node, title: String, onClickFunction: Function[_, T], id: Option[String] = None): dom.Node = { + val btnNode = document.createElement("button") + btnNode.appendChild(document.createTextNode(title)) + btnNode.setAttribute("type", "button") + btnNode.setAttribute("id", id.getOrElse("")) + btnNode.addEventListener("click", onClickFunction) + targetNode.appendChild(btnNode) + } +} \ No newline at end of file diff --git a/js/src/main/scala/kazari/model/EvaluatorConfig.scala b/js/src/main/scala/kazari/model/EvaluatorConfig.scala new file mode 100644 index 00000000..e4053a5c --- /dev/null +++ b/js/src/main/scala/kazari/model/EvaluatorConfig.scala @@ -0,0 +1,6 @@ +package kazari.model + +import scala.scalajs.js.annotation.JSExport + +@JSExport +case class EvaluatorConfig(url: String, authToken: String) \ No newline at end of file