Commit f8b0d4b5 authored by Mathieu leclaire's avatar Mathieu leclaire

Merge branch 'form'

Conflicts:
	client/src/main/scala/fr/iscpif/client/FlowChart.scala
parents 15e1244c aae3aec2
package client
import java.util.UUID
import org.scalajs.dom
import org.scalajs.dom.HTMLElement
import scala.concurrent.Future
import scalatags.JsDom._
import all._
......@@ -11,13 +8,9 @@ import tags2.section
import rx._
import scala.scalajs.js.annotation.JSExport
import scala.scalajs.concurrent.JSExecutionContext.Implicits.runNow
import org.scalajs.dom.extensions.Ajax
import scala.Some
import shared._
import upickle._
import autowire._
import JsRxTags._
@JSExport
object Client {
......@@ -47,7 +40,7 @@ object Post extends autowire.Client[String, upickle.Reader, upickle.Writer] {
override def doCall(req: Request): Future[String] = {
val url = req.path.mkString("/")
dom.extensions.Ajax.post(
dom.ext.Ajax.post(
url = "http://localhost:8080/" + url,
data = upickle.write(req.args)
).map {
......
package client
/*
* Copyright (C) 21/08/14 // mathieu.leclaire@openmole.org
* Copyright (C) 22/09/14 // mathieu.leclaire@openmole.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
......@@ -16,17 +16,16 @@ package client
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import fr.iscpif.scaladget.d3mapping._
import org.scalajs.dom
import fr.iscpif.scaladget.mapping._
import shared.Api
import org.scalajs.dom
import scala.scalajs.js
import js.Dynamic.{literal => lit, newInstance => jsnew}
import js.Dynamic.{ literal lit }
import rx._
import fr.iscpif.scaladget.d3._
import scala.scalajs.concurrent.JSExecutionContext.Implicits.runNow
import autowire._
import js.JSConverters._
trait GraphElement <: EventStates {
def literal: js.Dynamic
......@@ -57,35 +56,34 @@ class Window(nodes: Array[Task] = Array(), edges: Array[Edge] = Array()) {
val svg = d3.select("body")
.append("svg")
.attr("id", "workflow")
.attr("width", "2500px")
.attr("height", "2500px")
val graph = new GraphCreator(svg,
nodes,
edges
)
}
case class Consts(selectedClass: js.String = "selected",
case class Consts(selectedClass: String = "selected",
circleGClass: String = "conceptG",
graphClass: js.String = "graph",
activeEditId: js.String = "active-editing",
DELETE_KEY: js.Number = 46,
nodeRadius: js.Number = 50
)
graphClass: String = "graph",
activeEditId: String = "active-editing",
DELETE_KEY: Double = 46,
nodeRadius: Double = 50)
class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[Edge]) {
implicit def dynamicToString(d: js.Dynamic): String = d.asInstanceOf[js.String]
implicit def dynamicToString(d: js.Dynamic): String = d.asInstanceOf[String]
implicit def dynamicToBoolean(d: js.Dynamic): Boolean = d.asInstanceOf[js.Boolean]
implicit def dynamicToBoolean(d: js.Dynamic): Boolean = d.asInstanceOf[Boolean]
// SVG DEFINITIONS //
val consts = new Consts
val svgG = svgSelection.append("g").classed(consts.graphClass, true)
val dragLine = svgG.append("svg:path")
.attr("class", "link dragline hidden")
.attr("d", "M0,0L0,0")
......@@ -98,8 +96,8 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
val dragging: Var[Boolean] = Var(false)
svgSelection
.on("mousemove", (_: js.Any, _: js.Number) => mousemove)
.on("mouseup.scene", (_: js.Any, _: js.Number) => mouseup)
.on("mousemove", (_: js.Any, _: Double) mousemove)
.on("mouseup.scene", (_: js.Any, _: Double) mouseup)
// define arrow markers for graph links
defs.append("svg:marker")
......@@ -123,7 +121,6 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5")
val tasks: Var[Array[Var[Task]]] = Var(Array())
_tasks.map {
addTask
......@@ -134,25 +131,30 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
addEdge
}
val svgElement = js.Dynamic.global.document.getElementById("workflow")
// GLOBAL EVENTS //
d3.select(dom.window)
.on("keydown", (_: js.Any, _: js.Number) => {
d3.event.keyCode match {
case consts.DELETE_KEY =>
tasks().filter(t => t().selected()).map { t =>
removeTask(t)
}
edges().filter(e => e().selected()).map { e =>
removeEdge(e)
}
case _ =>
}
})
.on("keydown", (_: js.Any, _: Double) {
d3.event.keyCode match {
case consts.DELETE_KEY
tasks().filter(t t().selected()).map { t
removeTask(t)
}
edges().filter(e e().selected()).map { e
removeEdge(e)
}
case _
}
})
def mouseXY = d3.mouse(svgElement)
def mousemove = {
Seq(mouseDownTask()).flatten.map { t =>
val x = d3.event.clientX
val y = d3.event.clientY
Seq(mouseDownTask()).flatten.map { t
val xy = mouseXY
val x = xy(0)
val y = xy(1)
if (d3.event.shiftKey) {
dragging() = true
dragLine.attr("d", "M" + t.location()._1 + "," + t.location()._2 + "L" + x + "," + y)
......@@ -165,8 +167,9 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
def mouseup = {
// Hide the drag line
val xy = mouseXY
if (d3.event.shiftKey && !dragging()) {
val (x,y) = (d3.event.clientX, d3.event.clientY)
val (x, y) = (xy(0), xy(1))
Post[Api].uuid.call().foreach{ i=>
addTask(i, i, x, y)
......@@ -179,15 +182,14 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
.style("marker-end", " ")
}
// ADD, SELECT AND REMOVE ITEMS //
def unselectTasks = tasks().foreach { t => t().selected() = false}
def unselectTasks = tasks().foreach { t t().selected() = false }
def unselectEdges = edges().foreach { e => e().selected() = false}
def unselectEdges = edges().foreach { e e().selected() = false }
def removeTask(t: Var[Task]) = {
tasks() = tasks() diff Array(t)
edges() = edges().filterNot(e => e().source() == t() || e().target() == t())
edges() = edges().filterNot(e e().source() == t() || e().target() == t())
}
def removeEdge(e: Var[Edge]) = {
......@@ -200,7 +202,7 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
tasks() = tasks() :+ Var(task)
Obs(tasks) {
val mysel = circleRoot.selectAll("g").data(tasks(), (task: Var[Task], n: js.Number) => {
val mysel = circleRoot.selectAll("g").data(tasks().toJSArray, (task: Var[Task], n: Double) {
task().id.toString
})
......@@ -209,17 +211,17 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
Rx {
newG.classed(consts.circleGClass, true)
.attr("transform", (task: Var[Task]) => {
val loc = task().location()
"translate(" + loc._1 + "," + loc._2 + ")"
})
.attr("transform", (task: Var[Task]) {
val loc = task().location()
"translate(" + loc._1 + "," + loc._2 + ")"
})
newG.classed(consts.selectedClass, (task: Var[Task]) => {
newG.classed(consts.selectedClass, (task: Var[Task]) {
task().selected()
})
}
newG.on("mousedown", (t: Var[Task], n: js.Number) => {
newG.on("mousedown", (t: Var[Task], n: Double) {
mouseDownTask() = Some(t())
d3.event.stopPropagation
......@@ -228,7 +230,6 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
unselectEdges
t().selected() = !t().selected()
if (d3.event.shiftKey) {
val x = t().location()._1
val y = t().location()._2
......@@ -238,27 +239,26 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
.attr("d", "M" + x + "," + y + "L" + x + "," + y)
}
})
.on("mouseup.task", (t: Var[Task], n: js.Number) => {
Seq(mouseDownTask()).flatten.map { mdt =>
if (t() != mdt) {
addEdge(mdt, t())
.on("mouseup.task", (t: Var[Task], n: Double) {
Seq(mouseDownTask()).flatten.map { mdt
if (t() != mdt) {
addEdge(mdt, t())
}
}
}
}
)
mysel.exit().remove()
}
}
def addEdge(source: Task, target: Task): Unit = addEdge(new Edge(Var(source), Var(target)))
def addEdge(edge: Edge): Unit = {
edges() = edges() :+ Var(edge)
Obs(edges) {
val mysel = pathRoot.selectAll("path").data(edges(), (edge: Var[Edge], n: js.Number) => {
val mysel = pathRoot.selectAll("path").data(edges().toJSArray, (edge: Var[Edge], n: Double) {
edge().source().id + "+" + edge().target().id
})
......@@ -267,20 +267,20 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
Rx {
newPath.style("marker-end", "url(#end-arrow)")
.classed("link", true)
.attr("d", (edge: Var[Edge], n: js.Number) => {
val source = edge().source().location()
val target = edge().target().location()
"M" + source._1 + "," + source._2 + "L" + target._1 + "," + target._2
})
.attr("d", (edge: Var[Edge], n: Double) {
val source = edge().source().location()
val target = edge().target().location()
"M" + source._1 + "," + source._2 + "L" + target._1 + "," + target._2
})
// update existing paths
newPath.style("marker-end", "url(#end-arrow)")
.classed(consts.selectedClass, (edge: Var[Edge], n: Number) => {
edge().selected()
}
.classed(consts.selectedClass, (edge: Var[Edge], n: Number) {
edge().selected()
}
)
newPath.on("mousedown", (edge: Var[Edge], n: js.Number) => {
newPath.on("mousedown", (edge: Var[Edge], n: Double) {
unselectTasks
unselectEdges
edge().selected() = !edge().selected()
......@@ -291,4 +291,4 @@ class GraphCreator(svgSelection: Selection, _tasks: Array[Task], _edges: Array[E
mysel.exit().remove()
}
}
}
\ No newline at end of file
}
......@@ -47,7 +47,7 @@ object JsRxTags {
* the Obs onto the element itself so we have a reference to kill it when
* the element leaves the DOM (e.g. it gets deleted).
*/
implicit def rxMod[T <: dom.HTMLElement](r: Rx[HtmlTag]): Modifier = {
implicit def rxMod[T <: dom.raw.HTMLElement](r: Rx[HtmlTag]): Modifier = {
def rSafe = r.toTry match {
case Success(v) => v.render
case Failure(e) => span(e.toString, backgroundColor := "red").render
......
import sbt._
import Keys._
import org.scalatra.sbt._
import org.scalatra.sbt.PluginKeys._
import fr.iscpif.jsmanager.JSManagerPlugin._
import org.scalajs.sbtplugin.ScalaJSPlugin
import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._
object ScalaTraJSTagsWireRxBuild extends Build {
val Organization = "fr.iscpif"
val Name = "ScalaTraJSTagsWireRx"
val Version = "0.1.0-SNAPSHOT"
val ScalaVersion = "2.11.2"
val ScalaVersion = "2.11.6"
val ScalatraVersion = "2.3.0"
val Resolvers = Seq(Resolver.sonatypeRepo("snapshots"),
"Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/",
"bintray/non" at "http://dl.bintray.com/non/maven",
Resolver.url("scala-js-releases",
url("http://dl.bintray.com/content/scala-js/scala-js-releases"))(
Resolver.ivyStylePatterns))
"Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
)
lazy val shared = project.in(file("./shared")).settings(
scalaVersion := ScalaVersion
).settings(jsManagerSettings: _*)
)
lazy val client = Project(
"client",
file("./client"),
settings = Defaults.defaultSettings ++ jsManagerSettings ++ Seq(
settings = Seq(
version := Version,
scalaVersion := ScalaVersion,
resolvers ++= Resolvers,
libraryDependencies ++= Seq(
"com.lihaoyi" %%% "autowire" % "0.2.3",
"com.lihaoyi" %%% "upickle" % "0.2.5",
"com.scalatags" %%% "scalatags" % "0.4.2",
"com.scalarx" %%% "scalarx" % "0.2.6",
"fr.iscpif" %%% "scaladget" % "0.1.0",
"org.scala-lang.modules.scalajs" %%% "scalajs-dom" % "0.6"
),
//jsCall := "Client().run();",
outputPath := "server/src/main/webapp/"
"com.lihaoyi" %%% "autowire" % "0.2.5",
"com.lihaoyi" %%% "upickle" % "0.2.7",
"com.lihaoyi" %%% "scalatags" % "0.4.6",
"com.lihaoyi" %%% "scalarx" % "0.2.8",
"fr.iscpif" %%% "scaladget" % "0.5.0-SNAPSHOT",
"org.scala-js" %%% "scalajs-dom" % "0.8.0"
)
)
).dependsOn(shared)
).dependsOn(shared) enablePlugins (ScalaJSPlugin)
lazy val server = Project(
"server",
file("./server"),
settings = Defaults.defaultSettings ++ ScalatraPlugin.scalatraWithJRebel ++ Seq(
settings = ScalatraPlugin.scalatraWithJRebel ++ Seq(
organization := Organization,
name := Name,
version := Version,
scalaVersion := ScalaVersion,
resolvers ++= Resolvers,
libraryDependencies ++= Seq(
"com.lihaoyi" %% "autowire" % "0.2.3",
"com.lihaoyi" %% "upickle" % "0.2.5",
"com.scalatags" %% "scalatags" % "0.4.2",
"com.lihaoyi" %% "autowire" % "0.2.5",
"com.lihaoyi" %% "upickle" % "0.2.7",
"com.lihaoyi" %% "scalatags" % "0.4.6",
"org.scalatra" %% "scalatra" % ScalatraVersion,
"org.scalatra" %% "scalatra-specs2" % ScalatraVersion % "test",
"ch.qos.logback" % "logback-classic" % "1.0.12" % "runtime",
"org.eclipse.jetty" % "jetty-webapp" % "8.1.8.v20121106" % "container",
"org.eclipse.jetty" % "jetty-webapp" % "8.1.17.v20150415" % "container",
"org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container;provided;test" /*artifacts (Artifact("javax.servlet", "jar", "jar"))*/
)
)
......
sbt.version=0.13.5
sbt.version=0.13.7
resolvers ++= Seq(Resolver.url("scala-js-releases",
url("http://dl.bintray.com/content/scala-js/scala-js-releases"))(
Resolver.ivyStylePatterns))
resolvers += "Typesafe repository" at
"http://repo.typesafe.com/typesafe/releases/"
addSbtPlugin("fr.iscpif" %% "jsmanager" % "0.6.0")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.3")
addSbtPlugin("org.scalatra.sbt" % "scalatra-sbt" % "0.3.5")
package fr.iscpif.app
import java.util.UUID
import org.scalatra._
import scala.concurrent.ExecutionContext.Implicits.global
import upickle._
......@@ -19,8 +17,6 @@ object AutowireServer extends autowire.Server[String, upickle.Reader, upickle.Wr
}
object ApiImpl extends Api {
def hello(a: Int) = a * 3
def caseClass = MyCaseClass("Hello !")
}
class Servlet extends ScalatraServlet {
......
package shared
import scala.scalajs.js.annotation.JSExport
@JSExport
case class MyCaseClass(hello: String)
trait Api {
def hello(a: Int): Int
def caseClass(): MyCaseClass
def uuid(): String = java.util.UUID.randomUUID.toString
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment